smart-admin-web 10.21.0 → 10.22.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/dist/assets/icons/ph-subset.json.js +1 -1
- package/dist/composables/authMenuRoute.d.ts +10 -0
- package/dist/composables/authMenuRoute.js +39 -23
- package/dist/composables/authMenuRoute.js.map +1 -1
- package/dist/composables/useModule.d.ts +3 -1
- package/dist/composables/useModule.js +44 -32
- package/dist/composables/useModule.js.map +1 -1
- package/dist/index.js +49 -47
- package/dist/layouts/components/SideNav.vue.js +2 -2
- package/dist/layouts/components/SideNav2.vue.js.map +1 -1
- package/dist/lib/runtime.js +1 -1
- package/dist/locales/en-US.d.ts +6 -0
- package/dist/locales/en-US.js +9 -2
- package/dist/locales/en-US.js.map +1 -1
- package/dist/locales/zh-CN.d.ts +6 -0
- package/dist/locales/zh-CN.js +9 -2
- package/dist/locales/zh-CN.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/tree.d.ts +15 -0
- package/dist/utils/tree.js +43 -29
- package/dist/utils/tree.js.map +1 -1
- package/dist/utils/treeCard.d.ts +6 -0
- package/dist/utils/treeCard.js +9 -0
- package/dist/utils/treeCard.js.map +1 -0
- package/dist/views/error/404.vue.js +2 -2
- package/dist/views/error/4042.vue.js +81 -24
- package/dist/views/error/4042.vue.js.map +1 -1
- package/dist/views/login/components/LoginDesk.vue.js +2 -2
- package/dist/views/login/components/LoginDesk2.vue.js.map +1 -1
- package/dist/views/login/components/LoginHeroPanel.vue.js +2 -2
- package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -1
- package/dist/views/system/job-monitor/index.vue.js +2 -2
- package/dist/views/system/job-monitor/index2.vue.js +46 -46
- package/dist/views/system/job-monitor/index2.vue.js.map +1 -1
- package/dist/views/system/menu/index.vue.js +2 -2
- package/dist/views/system/menu/index2.vue.js +161 -150
- package/dist/views/system/menu/index2.vue.js.map +1 -1
- package/dist/views/system/org/index.vue.js +2 -2
- package/dist/views/system/org/index2.vue.js +182 -176
- package/dist/views/system/org/index2.vue.js.map +1 -1
- package/dist/views/system/user/index.vue.js +2 -2
- package/dist/views/system/user/index2.vue.js +348 -317
- package/dist/views/system/user/index2.vue.js.map +1 -1
- package/package.json +3 -3
package/dist/utils/tree.d.ts
CHANGED
|
@@ -26,6 +26,21 @@ export declare function expandableIds<T extends {
|
|
|
26
26
|
id: number;
|
|
27
27
|
children?: T[];
|
|
28
28
|
}>(nodes: T[]): number[];
|
|
29
|
+
/** 有子节点的根的 id —— 受控展开时用它播种"只展开一级":根展开、露出第二层,更深的层级仍收起。 */
|
|
30
|
+
export declare function rootExpandableIds<T extends {
|
|
31
|
+
id: number;
|
|
32
|
+
children?: T[];
|
|
33
|
+
}>(nodes: T[]): number[];
|
|
34
|
+
/**
|
|
35
|
+
* 树 → 深度优先平铺行(父在前、子紧随其后),每行带 depth(根 = 0),children 置空。
|
|
36
|
+
* 给窄档卡片列表用:smart-naive-table 的卡片模式只画传入的这一层行,不认 children,
|
|
37
|
+
* 树表在手机上要想看到子节点,就得由页面自己把整棵树摊成一列。行是浅拷贝,不改入参。
|
|
38
|
+
*/
|
|
39
|
+
export declare function flattenTree<T extends {
|
|
40
|
+
children?: T[];
|
|
41
|
+
}>(nodes: T[], depth?: number): Array<T & {
|
|
42
|
+
depth: number;
|
|
43
|
+
}>;
|
|
29
44
|
/** 收集 rootId 及其全部后代 id(平铺数组上按 parentId 迭代到不动点)。编辑机构选上级时剪自身子树防成环。 */
|
|
30
45
|
export declare function collectSubtreeIds<T extends {
|
|
31
46
|
id: number;
|
package/dist/utils/tree.js
CHANGED
|
@@ -1,47 +1,61 @@
|
|
|
1
|
-
function
|
|
2
|
-
const
|
|
3
|
-
for (const
|
|
1
|
+
function d(o) {
|
|
2
|
+
const e = /* @__PURE__ */ new Map();
|
|
3
|
+
for (const t of o) e.set(t.id, { ...t });
|
|
4
4
|
const n = [];
|
|
5
|
-
for (const
|
|
6
|
-
const
|
|
7
|
-
i ? (i.children ?? (i.children = [])).push(
|
|
5
|
+
for (const t of o) {
|
|
6
|
+
const r = e.get(t.id), i = e.get(t.parentId);
|
|
7
|
+
i ? (i.children ?? (i.children = [])).push(r) : n.push(r);
|
|
8
8
|
}
|
|
9
9
|
return n;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function s(o, e) {
|
|
12
12
|
const n = [];
|
|
13
|
-
for (const
|
|
14
|
-
if (
|
|
15
|
-
n.push(
|
|
13
|
+
for (const t of o) {
|
|
14
|
+
if (e(t)) {
|
|
15
|
+
n.push(t);
|
|
16
16
|
continue;
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
|
|
18
|
+
const r = s(t.children ?? [], e);
|
|
19
|
+
r.length && n.push({ ...t, children: r });
|
|
20
20
|
}
|
|
21
21
|
return n;
|
|
22
22
|
}
|
|
23
|
-
function
|
|
24
|
-
const
|
|
25
|
-
var
|
|
26
|
-
for (const i of
|
|
27
|
-
(
|
|
23
|
+
function f(o) {
|
|
24
|
+
const e = [], n = (t) => {
|
|
25
|
+
var r;
|
|
26
|
+
for (const i of t)
|
|
27
|
+
(r = i.children) != null && r.length && (e.push(i.id), n(i.children));
|
|
28
28
|
};
|
|
29
|
-
return n(
|
|
29
|
+
return n(o), e;
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
function l(o) {
|
|
32
|
+
return o.filter((e) => {
|
|
33
|
+
var n;
|
|
34
|
+
return (n = e.children) == null ? void 0 : n.length;
|
|
35
|
+
}).map((e) => e.id);
|
|
36
|
+
}
|
|
37
|
+
function c(o, e = 0) {
|
|
38
|
+
return o.flatMap((n) => [
|
|
39
|
+
{ ...n, children: [], depth: e },
|
|
40
|
+
...c(n.children ?? [], e + 1)
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
function u(o, e) {
|
|
44
|
+
const n = /* @__PURE__ */ new Set([e]);
|
|
45
|
+
let t = !0;
|
|
46
|
+
for (; t; ) {
|
|
47
|
+
t = !1;
|
|
48
|
+
for (const r of o)
|
|
49
|
+
!n.has(r.id) && n.has(r.parentId) && (n.add(r.id), t = !0);
|
|
38
50
|
}
|
|
39
51
|
return n;
|
|
40
52
|
}
|
|
41
53
|
export {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
d as buildTree,
|
|
55
|
+
u as collectSubtreeIds,
|
|
56
|
+
f as expandableIds,
|
|
57
|
+
s as filterTree,
|
|
58
|
+
c as flattenTree,
|
|
59
|
+
l as rootExpandableIds
|
|
46
60
|
};
|
|
47
61
|
//# sourceMappingURL=tree.js.map
|
package/dist/utils/tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","sources":["../../src/utils/tree.ts"],"sourcesContent":["/** 平铺列表 → 树。按 parentId 挂到父的 children;根 = parentId 不在集合内(含 0)。\n * 原序保留(输入通常已按 sort、id 排好);孤儿(父不存在)兜底当根,不丢数据。\n * 两个消费点:OrgTreeSelect、机构管理页。 */\nexport type Tree<T> = T & { children?: Tree<T>[] }\n\nexport function buildTree<T extends { id: number; parentId: number }>(flat: T[]): Tree<T>[] {\n const map = new Map<number, Tree<T>>()\n for (const item of flat) map.set(item.id, { ...item })\n const roots: Tree<T>[] = []\n for (const item of flat) {\n const node = map.get(item.id)!\n const parent = map.get(item.parentId)\n if (parent) (parent.children ??= []).push(node)\n else roots.push(node)\n }\n return roots\n}\n\n/**\n * 按谓词剪枝:命中的节点保留(连同它的整棵子树——搜到一个目录,自然想看它下面有什么),\n * 未命中但有后代命中的节点作为**祖先链**保留(否则命中的节点在树里无处安放,只剩一堆没有上下文的叶子)。\n *\n * 命中节点返回的是**原对象引用**(零拷贝);只有\"仅因后代命中而保留\"的祖先才是浅拷贝(children 换成剪过的分支)。\n * 因此在搜索态下,直接往行对象上写值(`r.enabled = v`)对这些祖先行不会回写到源树 ——\n * 调用方要么改从源树写,要么变更后重拉(机构页选了后者,与它其余所有变更的做法一致)。\n *\n * 两个消费点:菜单管理页、机构管理页。\n */\nexport function filterTree<T extends { children?: T[] }>(\n nodes: T[],\n match: (node: T) => boolean,\n): T[] {\n const out: T[] = []\n for (const node of nodes) {\n if (match(node)) {\n out.push(node)\n continue\n }\n const kids = filterTree(node.children ?? [], match)\n if (kids.length) out.push({ ...node, children: kids })\n }\n return out\n}\n\n/** 收集树中所有\"可展开\"节点(有子节点)的 id —— 受控展开时用它播种\"全部展开\"。 */\nexport function expandableIds<T extends { id: number; children?: T[] }>(nodes: T[]): number[] {\n const ids: number[] = []\n const walk = (list: T[]) => {\n for (const n of list) {\n if (n.children?.length) {\n ids.push(n.id)\n walk(n.children)\n }\n }\n }\n walk(nodes)\n return ids\n}\n\n/** 收集 rootId 及其全部后代 id(平铺数组上按 parentId 迭代到不动点)。编辑机构选上级时剪自身子树防成环。 */\nexport function collectSubtreeIds<T extends { id: number; parentId: number }>(\n flat: T[],\n rootId: number,\n): Set<number> {\n const ids = new Set<number>([rootId])\n let grew = true\n while (grew) {\n grew = false\n for (const item of flat) {\n if (!ids.has(item.id) && ids.has(item.parentId)) {\n ids.add(item.id)\n grew = true\n }\n }\n }\n return ids\n}\n"],"names":["buildTree","flat","map","item","roots","node","parent","filterTree","nodes","match","out","kids","expandableIds","ids","walk","list","_a","n","collectSubtreeIds","rootId","grew"],"mappings":"AAKO,SAASA,EAAsDC,GAAsB;AAC1F,QAAMC,wBAAU,IAAA;AAChB,aAAWC,KAAQF,EAAM,CAAAC,EAAI,IAAIC,EAAK,IAAI,EAAE,GAAGA,GAAM;AACrD,QAAMC,IAAmB,CAAA;AACzB,aAAWD,KAAQF,GAAM;AACvB,UAAMI,IAAOH,EAAI,IAAIC,EAAK,EAAE,GACtBG,IAASJ,EAAI,IAAIC,EAAK,QAAQ;AACpC,IAAIG,KAASA,EAAO,aAAPA,EAAO,WAAa,CAAA,IAAI,KAAKD,CAAI,IACzCD,EAAM,KAAKC,CAAI;AAAA,EACtB;AACA,SAAOD;AACT;AAYO,SAASG,EACdC,GACAC,GACK;AACL,QAAMC,IAAW,CAAA;AACjB,aAAWL,KAAQG,GAAO;AACxB,QAAIC,EAAMJ,CAAI,GAAG;AACf,MAAAK,EAAI,KAAKL,CAAI;AACb;AAAA,IACF;AACA,UAAMM,IAAOJ,EAAWF,EAAK,YAAY,CAAA,GAAII,CAAK;AAClD,IAAIE,EAAK,UAAQD,EAAI,KAAK,EAAE,GAAGL,GAAM,UAAUM,GAAM;AAAA,EACvD;AACA,SAAOD;AACT;AAGO,SAASE,EAAwDJ,GAAsB;AAC5F,QAAMK,IAAgB,CAAA,GAChBC,IAAO,CAACC,MAAc;AA1CvB,QAAAC;AA2CH,eAAWC,KAAKF;AACd,OAAIC,IAAAC,EAAE,aAAF,QAAAD,EAAY,WACdH,EAAI,KAAKI,EAAE,EAAE,GACbH,EAAKG,EAAE,QAAQ;AAAA,EAGrB;AACA,SAAAH,EAAKN,CAAK,GACHK;AACT;AAGO,SAASK,
|
|
1
|
+
{"version":3,"file":"tree.js","sources":["../../src/utils/tree.ts"],"sourcesContent":["/** 平铺列表 → 树。按 parentId 挂到父的 children;根 = parentId 不在集合内(含 0)。\n * 原序保留(输入通常已按 sort、id 排好);孤儿(父不存在)兜底当根,不丢数据。\n * 两个消费点:OrgTreeSelect、机构管理页。 */\nexport type Tree<T> = T & { children?: Tree<T>[] }\n\nexport function buildTree<T extends { id: number; parentId: number }>(flat: T[]): Tree<T>[] {\n const map = new Map<number, Tree<T>>()\n for (const item of flat) map.set(item.id, { ...item })\n const roots: Tree<T>[] = []\n for (const item of flat) {\n const node = map.get(item.id)!\n const parent = map.get(item.parentId)\n if (parent) (parent.children ??= []).push(node)\n else roots.push(node)\n }\n return roots\n}\n\n/**\n * 按谓词剪枝:命中的节点保留(连同它的整棵子树——搜到一个目录,自然想看它下面有什么),\n * 未命中但有后代命中的节点作为**祖先链**保留(否则命中的节点在树里无处安放,只剩一堆没有上下文的叶子)。\n *\n * 命中节点返回的是**原对象引用**(零拷贝);只有\"仅因后代命中而保留\"的祖先才是浅拷贝(children 换成剪过的分支)。\n * 因此在搜索态下,直接往行对象上写值(`r.enabled = v`)对这些祖先行不会回写到源树 ——\n * 调用方要么改从源树写,要么变更后重拉(机构页选了后者,与它其余所有变更的做法一致)。\n *\n * 两个消费点:菜单管理页、机构管理页。\n */\nexport function filterTree<T extends { children?: T[] }>(\n nodes: T[],\n match: (node: T) => boolean,\n): T[] {\n const out: T[] = []\n for (const node of nodes) {\n if (match(node)) {\n out.push(node)\n continue\n }\n const kids = filterTree(node.children ?? [], match)\n if (kids.length) out.push({ ...node, children: kids })\n }\n return out\n}\n\n/** 收集树中所有\"可展开\"节点(有子节点)的 id —— 受控展开时用它播种\"全部展开\"。 */\nexport function expandableIds<T extends { id: number; children?: T[] }>(nodes: T[]): number[] {\n const ids: number[] = []\n const walk = (list: T[]) => {\n for (const n of list) {\n if (n.children?.length) {\n ids.push(n.id)\n walk(n.children)\n }\n }\n }\n walk(nodes)\n return ids\n}\n\n/** 有子节点的根的 id —— 受控展开时用它播种\"只展开一级\":根展开、露出第二层,更深的层级仍收起。 */\nexport function rootExpandableIds<T extends { id: number; children?: T[] }>(nodes: T[]): number[] {\n return nodes.filter(n => n.children?.length).map(n => n.id)\n}\n\n/**\n * 树 → 深度优先平铺行(父在前、子紧随其后),每行带 depth(根 = 0),children 置空。\n * 给窄档卡片列表用:smart-naive-table 的卡片模式只画传入的这一层行,不认 children,\n * 树表在手机上要想看到子节点,就得由页面自己把整棵树摊成一列。行是浅拷贝,不改入参。\n */\nexport function flattenTree<T extends { children?: T[] }>(\n nodes: T[],\n depth = 0,\n): Array<T & { depth: number }> {\n return nodes.flatMap(node => [\n { ...node, children: [], depth } as T & { depth: number },\n ...flattenTree(node.children ?? [], depth + 1),\n ])\n}\n\n/** 收集 rootId 及其全部后代 id(平铺数组上按 parentId 迭代到不动点)。编辑机构选上级时剪自身子树防成环。 */\nexport function collectSubtreeIds<T extends { id: number; parentId: number }>(\n flat: T[],\n rootId: number,\n): Set<number> {\n const ids = new Set<number>([rootId])\n let grew = true\n while (grew) {\n grew = false\n for (const item of flat) {\n if (!ids.has(item.id) && ids.has(item.parentId)) {\n ids.add(item.id)\n grew = true\n }\n }\n }\n return ids\n}\n"],"names":["buildTree","flat","map","item","roots","node","parent","filterTree","nodes","match","out","kids","expandableIds","ids","walk","list","_a","n","rootExpandableIds","flattenTree","depth","collectSubtreeIds","rootId","grew"],"mappings":"AAKO,SAASA,EAAsDC,GAAsB;AAC1F,QAAMC,wBAAU,IAAA;AAChB,aAAWC,KAAQF,EAAM,CAAAC,EAAI,IAAIC,EAAK,IAAI,EAAE,GAAGA,GAAM;AACrD,QAAMC,IAAmB,CAAA;AACzB,aAAWD,KAAQF,GAAM;AACvB,UAAMI,IAAOH,EAAI,IAAIC,EAAK,EAAE,GACtBG,IAASJ,EAAI,IAAIC,EAAK,QAAQ;AACpC,IAAIG,KAASA,EAAO,aAAPA,EAAO,WAAa,CAAA,IAAI,KAAKD,CAAI,IACzCD,EAAM,KAAKC,CAAI;AAAA,EACtB;AACA,SAAOD;AACT;AAYO,SAASG,EACdC,GACAC,GACK;AACL,QAAMC,IAAW,CAAA;AACjB,aAAWL,KAAQG,GAAO;AACxB,QAAIC,EAAMJ,CAAI,GAAG;AACf,MAAAK,EAAI,KAAKL,CAAI;AACb;AAAA,IACF;AACA,UAAMM,IAAOJ,EAAWF,EAAK,YAAY,CAAA,GAAII,CAAK;AAClD,IAAIE,EAAK,UAAQD,EAAI,KAAK,EAAE,GAAGL,GAAM,UAAUM,GAAM;AAAA,EACvD;AACA,SAAOD;AACT;AAGO,SAASE,EAAwDJ,GAAsB;AAC5F,QAAMK,IAAgB,CAAA,GAChBC,IAAO,CAACC,MAAc;AA1CvB,QAAAC;AA2CH,eAAWC,KAAKF;AACd,OAAIC,IAAAC,EAAE,aAAF,QAAAD,EAAY,WACdH,EAAI,KAAKI,EAAE,EAAE,GACbH,EAAKG,EAAE,QAAQ;AAAA,EAGrB;AACA,SAAAH,EAAKN,CAAK,GACHK;AACT;AAGO,SAASK,EAA4DV,GAAsB;AAChG,SAAOA,EAAM,OAAO,CAAAS,MAAA;AAxDf,QAAAD;AAwDoB,YAAAA,IAAAC,EAAE,aAAF,gBAAAD,EAAY;AAAA,GAAM,EAAE,IAAI,CAAAC,MAAKA,EAAE,EAAE;AAC5D;AAOO,SAASE,EACdX,GACAY,IAAQ,GACsB;AAC9B,SAAOZ,EAAM,QAAQ,CAAAH,MAAQ;AAAA,IAC3B,EAAE,GAAGA,GAAM,UAAU,CAAA,GAAI,OAAAe,EAAA;AAAA,IACzB,GAAGD,EAAYd,EAAK,YAAY,CAAA,GAAIe,IAAQ,CAAC;AAAA,EAAA,CAC9C;AACH;AAGO,SAASC,EACdpB,GACAqB,GACa;AACb,QAAMT,IAAM,oBAAI,IAAY,CAACS,CAAM,CAAC;AACpC,MAAIC,IAAO;AACX,SAAOA,KAAM;AACX,IAAAA,IAAO;AACP,eAAWpB,KAAQF;AACjB,MAAI,CAACY,EAAI,IAAIV,EAAK,EAAE,KAAKU,EAAI,IAAIV,EAAK,QAAQ,MAC5CU,EAAI,IAAIV,EAAK,EAAE,GACfoB,IAAO;AAAA,EAGb;AACA,SAAOV;AACT;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"treeCard.js","sources":["../../src/utils/treeCard.ts"],"sourcesContent":["import { h, type VNodeChild } from 'vue'\n\n/**\n * 窄档卡片里没有树的缩进:按 `flattenTree` 给的 depth 给标题缩进,层级一眼可辨。\n * 宽档的行没有 depth,原样返回,由表格自己画缩进与展开箭头。\n */\nexport const indentByDepth = (row: object, content: VNodeChild): VNodeChild => {\n const depth = (row as { depth?: number }).depth\n return depth\n ? h('span', { style: { paddingInlineStart: `${depth * 16}px` } }, [content])\n : content\n}\n"],"names":["indentByDepth","row","content","depth","h"],"mappings":";AAMO,MAAMA,IAAgB,CAACC,GAAaC,MAAoC;AAC7E,QAAMC,IAASF,EAA2B;AAC1C,SAAOE,IACHC,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,GAAGD,IAAQ,EAAE,OAAK,GAAK,CAACD,CAAO,CAAC,IACzEA;AACN;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import o from "./4042.vue.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import t from "../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const
|
|
4
|
+
const e = /* @__PURE__ */ t(o, [["__scopeId", "data-v-ce3af4ea"]]);
|
|
5
5
|
export {
|
|
6
|
-
|
|
6
|
+
e as default
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=404.vue.js.map
|
|
@@ -1,33 +1,90 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { useRouter as
|
|
3
|
-
import { NCard as
|
|
4
|
-
import { useI18n as
|
|
5
|
-
|
|
1
|
+
import { defineComponent as V, computed as m, ref as C, watch as E, openBlock as r, createBlock as f, unref as e, withCtx as s, createElementVNode as i, toDisplayString as u, createElementBlock as I, createCommentVNode as v, createTextVNode as h, createVNode as O } from "vue";
|
|
2
|
+
import { useRoute as b, useRouter as z } from "vue-router";
|
|
3
|
+
import { useMessage as R, NCard as S, NButton as y } from "naive-ui";
|
|
4
|
+
import { useI18n as T } from "vue-i18n";
|
|
5
|
+
import { useAuthStore as $ } from "../../stores/auth.js";
|
|
6
|
+
import { useModule as D } from "../../composables/useModule.js";
|
|
7
|
+
import { translateMenuTitle as M } from "../../locales/menuTitle.js";
|
|
8
|
+
import { translateError as P } from "../../utils/error.js";
|
|
9
|
+
const j = {
|
|
6
10
|
class: "nf",
|
|
7
11
|
role: "status"
|
|
8
|
-
},
|
|
12
|
+
}, q = { class: "msg" }, G = {
|
|
13
|
+
key: 0,
|
|
14
|
+
class: "hint"
|
|
15
|
+
}, H = { class: "actions" }, ee = /* @__PURE__ */ V({
|
|
9
16
|
__name: "404",
|
|
10
|
-
setup(
|
|
11
|
-
const
|
|
12
|
-
|
|
17
|
+
setup(J) {
|
|
18
|
+
const _ = b(), k = z(), N = R(), { t: a } = T(), c = $(), { findOwnerModule: A, switchModule: F } = D(), d = m(() => c.modules.length > 1), w = m(() => {
|
|
19
|
+
const n = c.modules.find((o) => o.id === c.currentModuleId);
|
|
20
|
+
return n ? M(n.title) : "";
|
|
21
|
+
}), t = C(null), g = m(() => t.value ? M(t.value.title) : ""), l = C(!1);
|
|
22
|
+
let x = 0;
|
|
23
|
+
E(
|
|
24
|
+
() => _.path,
|
|
25
|
+
async (n) => {
|
|
26
|
+
if (t.value = null, !d.value) return;
|
|
27
|
+
const o = ++x, p = await A(n);
|
|
28
|
+
o === x && (t.value = p);
|
|
29
|
+
},
|
|
30
|
+
{ immediate: !0 }
|
|
31
|
+
);
|
|
32
|
+
async function B() {
|
|
33
|
+
if (!(!t.value || l.value)) {
|
|
34
|
+
l.value = !0;
|
|
35
|
+
try {
|
|
36
|
+
await F(t.value.id, _.fullPath);
|
|
37
|
+
} catch (n) {
|
|
38
|
+
N.error(P(n));
|
|
39
|
+
} finally {
|
|
40
|
+
l.value = !1;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return (n, o) => (r(), f(e(S), {
|
|
13
45
|
class: "nf-card",
|
|
14
46
|
"content-style": "padding: 40px 28px 36px"
|
|
15
47
|
}, {
|
|
16
48
|
default: s(() => [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
49
|
+
i("div", j, [
|
|
50
|
+
o[2] || (o[2] = i("div", { class: "code" }, "404", -1)),
|
|
51
|
+
i("div", q, u(t.value ? e(a)("notFound.otherApp", { app: g.value }) : e(a)("notFound.desc")), 1),
|
|
52
|
+
d.value && w.value ? (r(), I("div", G, u(e(a)("notFound.currentApp", { app: w.value })), 1)) : v("", !0),
|
|
53
|
+
i("div", H, [
|
|
54
|
+
t.value ? (r(), f(e(y), {
|
|
55
|
+
key: 0,
|
|
56
|
+
type: "primary",
|
|
57
|
+
size: "large",
|
|
58
|
+
loading: l.value,
|
|
59
|
+
onClick: B
|
|
60
|
+
}, {
|
|
61
|
+
default: s(() => [
|
|
62
|
+
h(u(e(a)("notFound.switchAndOpen", { app: g.value })), 1)
|
|
63
|
+
]),
|
|
64
|
+
_: 1
|
|
65
|
+
}, 8, ["loading"])) : v("", !0),
|
|
66
|
+
O(e(y), {
|
|
67
|
+
type: t.value ? "default" : "primary",
|
|
68
|
+
size: "large",
|
|
69
|
+
class: "back",
|
|
70
|
+
onClick: o[0] || (o[0] = (p) => e(k).replace("/"))
|
|
71
|
+
}, {
|
|
72
|
+
default: s(() => [
|
|
73
|
+
h(u(e(a)("notFound.back")), 1)
|
|
74
|
+
]),
|
|
75
|
+
_: 1
|
|
76
|
+
}, 8, ["type"]),
|
|
77
|
+
d.value && !t.value ? (r(), f(e(y), {
|
|
78
|
+
key: 1,
|
|
79
|
+
text: "",
|
|
80
|
+
onClick: o[1] || (o[1] = (p) => e(k).push("/module"))
|
|
81
|
+
}, {
|
|
82
|
+
default: s(() => [
|
|
83
|
+
h(u(e(a)("app.switchModule")), 1)
|
|
84
|
+
]),
|
|
85
|
+
_: 1
|
|
86
|
+
})) : v("", !0)
|
|
87
|
+
])
|
|
31
88
|
])
|
|
32
89
|
]),
|
|
33
90
|
_: 1
|
|
@@ -35,6 +92,6 @@ const x = {
|
|
|
35
92
|
}
|
|
36
93
|
});
|
|
37
94
|
export {
|
|
38
|
-
|
|
95
|
+
ee as default
|
|
39
96
|
};
|
|
40
97
|
//# sourceMappingURL=4042.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"4042.vue.js","sources":["../../../src/views/error/404.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useRouter } from 'vue-router'\nimport { NButton, NCard } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\n\nconst router = useRouter()\nconst { t } = useI18n()\n</script>\n\n<template>\n <!-- 404 挂在布局壳内:撑满内容区,居中块放进卡片里(文字直接压在画布柔光上对比度不够) -->\n <n-card class=\"nf-card\" content-style=\"padding: 40px 28px 36px\">\n <div class=\"nf\" role=\"status\">\n <div class=\"code\">404</div>\n <div class=\"msg\"
|
|
1
|
+
{"version":3,"file":"4042.vue.js","sources":["../../../src/views/error/404.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useRoute, useRouter } from 'vue-router'\nimport { NButton, NCard, useMessage } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { useAuthStore } from '#/stores/auth'\nimport { useModule } from '#/composables/useModule'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { translateError } from '#/utils/error'\nimport type { AppModule } from '#/types/menu'\n\nconst route = useRoute()\nconst router = useRouter()\nconst message = useMessage()\nconst { t } = useI18n()\nconst auth = useAuthStore()\nconst { findOwnerModule, switchModule } = useModule()\n\n// 动态路由只注册当前应用的菜单:别的应用的页面地址(书签、第三方后台配的主页)在这里同样是 404。\n// 单应用部署没有\"别的应用\",也就不提应用、不反查。\nconst multiApp = computed(() => auth.modules.length > 1)\nconst currentApp = computed(() => {\n const m = auth.modules.find(x => x.id === auth.currentModuleId)\n return m ? translateMenuTitle(m.title) : ''\n})\n\nconst owner = ref<AppModule | null>(null)\nconst ownerName = computed(() => (owner.value ? translateMenuTitle(owner.value.title) : ''))\nconst switching = ref(false)\n\n// 同一个组件实例会随地址变化复用,较早发出的反查晚到时不能盖掉较新地址的结果\nlet lookup = 0\nwatch(\n () => route.path,\n async path => {\n owner.value = null\n if (!multiApp.value) return\n const mine = ++lookup\n const found = await findOwnerModule(path)\n if (mine === lookup) owner.value = found\n },\n { immediate: true },\n)\n\nasync function openInOwner() {\n if (!owner.value || switching.value) return\n switching.value = true\n try {\n await switchModule(owner.value.id, route.fullPath)\n } catch (e) {\n message.error(translateError(e))\n } finally {\n switching.value = false\n }\n}\n</script>\n\n<template>\n <!-- 404 挂在布局壳内:撑满内容区,居中块放进卡片里(文字直接压在画布柔光上对比度不够) -->\n <n-card class=\"nf-card\" content-style=\"padding: 40px 28px 36px\">\n <div class=\"nf\" role=\"status\">\n <div class=\"code\">404</div>\n <div class=\"msg\">\n {{ owner ? t('notFound.otherApp', { app: ownerName }) : t('notFound.desc') }}\n </div>\n <div v-if=\"multiApp && currentApp\" class=\"hint\">\n {{ t('notFound.currentApp', { app: currentApp }) }}\n </div>\n <div class=\"actions\">\n <n-button\n v-if=\"owner\"\n type=\"primary\"\n size=\"large\"\n :loading=\"switching\"\n @click=\"openInOwner\"\n >\n {{ t('notFound.switchAndOpen', { app: ownerName }) }}\n </n-button>\n <n-button\n :type=\"owner ? 'default' : 'primary'\"\n size=\"large\"\n class=\"back\"\n @click=\"router.replace('/')\"\n >\n {{ t('notFound.back') }}\n </n-button>\n <n-button v-if=\"multiApp && !owner\" text @click=\"router.push('/module')\">\n {{ t('app.switchModule') }}\n </n-button>\n </div>\n </div>\n </n-card>\n</template>\n\n<style scoped>\n/* 撑满 layout 的 .page 容器,而不是整个视口——404 挂在布局壳内 */\n.nf-card {\n min-height: 60vh;\n height: 100%;\n}\n.nf-card :deep(.n-card__content) {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.nf {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 16px;\n}\n.code {\n font-size: 96px;\n font-weight: 800;\n line-height: 1;\n letter-spacing: -0.04em;\n color: var(--signal);\n}\n.msg {\n color: var(--text-2);\n font-size: 16px;\n}\n.hint {\n color: var(--text-3);\n font-size: 13px;\n}\n.actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: 12px;\n}\n.back {\n min-width: 120px;\n}\n</style>\n"],"names":["route","useRoute","router","useRouter","message","useMessage","t","useI18n","auth","useAuthStore","findOwnerModule","switchModule","useModule","multiApp","computed","currentApp","m","x","translateMenuTitle","owner","ref","ownerName","switching","lookup","watch","path","mine","found","openInOwner","e","translateError","_createBlock","_unref","NCard","_createElementVNode","_hoisted_1","_cache","_hoisted_2","_toDisplayString","_openBlock","_createElementBlock","_hoisted_3","_hoisted_4","NButton","_createTextVNode","_createVNode","$event"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import o from "./LoginDesk2.vue.js";
|
|
|
2
2
|
/* empty css */
|
|
3
3
|
/* empty css */
|
|
4
4
|
import t from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
5
|
-
const
|
|
5
|
+
const i = /* @__PURE__ */ t(o, [["__scopeId", "data-v-e8bd5462"]]);
|
|
6
6
|
export {
|
|
7
|
-
|
|
7
|
+
i as default
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=LoginDesk.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginDesk2.vue.js","sources":["../../../../src/views/login/components/LoginDesk.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 入口类全屏页(登录 / 二次验证 / 第三方回调 / 门户加载失败)共用的外壳:macOS 锁屏语言。\n// 整页一张慢慢飘的柔光色场(.desk,颜色全由强调色推导,无网格)+ 浮在上面的毛玻璃卡,右上角是工具栏。\n// 单栏 = 居中一张卡;双栏(split)= 左栏品牌区(brand 插槽)压在色场上,右栏是这张卡。\n// 只管视觉外壳:卡里放什么、表单怎么提交都在各页自己手里。\n//\n// 动效(全部不回弹):入场按「卡 → 标题 → 字段 → 按钮」依次浮现(先模糊后清晰);\n// 色场与卡跟着指针做反向视差;leaving 为真时整页淡出放大一点(像 macOS 解锁),给登录成功收尾。\nimport { onBeforeUnmount, ref } from 'vue'\nimport { NButton, NCard, NTooltip } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useAppStore } from '#/stores/app'\n\nwithDefaults(\n defineProps<{\n /** 双栏:左栏渲染 brand 插槽,卡片宽度收到 384 */\n split?: boolean\n /** 卡片宽度(px),窄屏被 max-width:100% 收住 */\n width?: number\n /** NCard 内容区内边距 */\n contentStyle?: string\n /** 退场:登录成功后由页面置真,整页淡出,等动画播完再跳转 */\n leaving?: boolean\n }>(),\n { split: false, width: 400, contentStyle: 'padding: 26px 26px 22px', leaving: false },\n)\n\nconst app = useAppStore()\nconst { t } = useI18n()\n\n// 指针视差:只认鼠标(触屏没有悬停位置),坐标归一到 -1..1 写成 CSS 变量,位移与过渡都在 CSS 里。\n// 另外把指针相对卡片左上角的位置(--mx / --my,px)和「指针在窗口内」(--lit)写出来,\n// 给卡片面上那束跟着指针走的柔光用:指针停在卡片上时视差位移趋近于零,光斑是这时唯一的反馈。\nconst root = ref<HTMLElement | null>(null)\nlet raf = 0\nfunction setPointer(x: number, y: number, clientX?: number, clientY?: number) {\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n const el = root.value\n if (!el) return\n el.style.setProperty('--px', x.toFixed(3))\n el.style.setProperty('--py', y.toFixed(3))\n if (clientX === undefined || clientY === undefined) {\n // 指针离开:只熄灭柔光,保留最后位置,淡出时光斑不跳\n el.style.setProperty('--lit', '0')\n return\n }\n const card = el.querySelector('.desk-card')?.getBoundingClientRect()\n if (card) {\n el.style.setProperty('--mx', `${(clientX - card.left).toFixed(1)}px`)\n el.style.setProperty('--my', `${(clientY - card.top).toFixed(1)}px`)\n }\n el.style.setProperty('--lit', '1')\n })\n}\nfunction onPointerMove(e: PointerEvent) {\n if (e.pointerType !== 'mouse') return\n setPointer(\n (e.clientX / window.innerWidth) * 2 - 1,\n (e.clientY / window.innerHeight) * 2 - 1,\n e.clientX,\n e.clientY,\n )\n}\nonBeforeUnmount(() => cancelAnimationFrame(raf))\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"login desk-bg\"\n :class=\"{ split, leaving }\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"setPointer(0, 0)\"\n >\n <div class=\"desk\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n <i />\n </div>\n\n <div v-if=\"split\" class=\"login-brand\">\n <div class=\"login-brand-inner\"><slot name=\"brand\" /></div>\n </div>\n\n <div class=\"login-stage\">\n <!-- 右上角工具栏:页面自己的按钮(布局切换、语言)在前,主题切换永远贴最右角 -->\n <div class=\"login-corner\">\n <slot name=\"corner\" />\n <n-tooltip>\n <template #trigger>\n <n-button\n quaternary\n circle\n :aria-label=\"app.isDark ? t('app.light') : t('app.dark')\"\n @click=\"app.toggleDark()\"\n >\n <template #icon>\n <Icon :icon=\"app.isDark ? 'ph:moon' : 'ph:sun'\" :width=\"18\" />\n </template>\n </n-button>\n </template>\n {{ app.isDark ? t('app.light') : t('app.dark') }}\n </n-tooltip>\n </div>\n\n <!-- margin-top 给右上角工具栏留位:窄屏内容比视口高时,顶部不会被工具栏盖住 -->\n <div\n class=\"login-card\"\n :class=\"{ 'on-desk': split }\"\n :style=\"split ? undefined : { width: `${width}px` }\"\n >\n <slot name=\"above\" />\n <n-card :bordered=\"true\" class=\"desk-card\" :content-style=\"contentStyle\">\n <slot />\n </n-card>\n <slot name=\"after\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* 登录页(单栏 / 双栏都算)是 macOS 桌面那种纯色场:不要网格线,不要透视地面 */\n.login {\n /* 减速到底、不过冲:入场与视差共用这条曲线 */\n --rise: cubic-bezier(0.22, 1, 0.36, 1);\n min-height: 100dvh;\n background: var(--desk-base);\n position: relative;\n overflow: hidden;\n}\n.login.split {\n display: grid;\n grid-template-columns: minmax(340px, 46%) 1fr;\n}\n.login-stage {\n min-height: 100dvh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n position: relative;\n overflow: hidden;\n}\n\n/* 色场:四团 blur(70px) 的柔光球慢速漂移,颜色由强调色推导(--desk-1..4);\n 整体再按指针反向平移一点(用独立的 translate 属性,不和漂移动画的 transform 打架) */\n.desk {\n position: absolute;\n inset: -20%;\n pointer-events: none;\n z-index: 0;\n translate: calc(var(--px, 0) * -44px) calc(var(--py, 0) * -30px);\n transition: translate 1.2s var(--rise);\n}\n.desk i {\n position: absolute;\n display: block;\n border-radius: 50%;\n filter: blur(70px);\n opacity: var(--desk-op);\n}\n.desk i:nth-child(1) {\n left: 2%;\n top: 4%;\n width: 46%;\n height: 62%;\n background: var(--desk-1);\n animation: drift1 26s ease-in-out infinite alternate;\n}\n.desk i:nth-child(2) {\n left: 26%;\n top: 34%;\n width: 44%;\n height: 56%;\n background: var(--desk-2);\n animation: drift2 32s ease-in-out infinite alternate;\n}\n.desk i:nth-child(3) {\n left: 54%;\n top: -6%;\n width: 40%;\n height: 58%;\n background: var(--desk-3);\n animation: drift3 29s ease-in-out infinite alternate;\n}\n.desk i:nth-child(4) {\n left: 62%;\n top: 46%;\n width: 46%;\n height: 62%;\n background: var(--desk-4);\n animation: drift1 35s ease-in-out infinite alternate-reverse;\n}\n@keyframes drift1 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(6%, -5%, 0) scale(1.12);\n }\n}\n@keyframes drift2 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(-7%, 4%, 0) scale(1.08);\n }\n}\n@keyframes drift3 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(4%, 7%, 0) scale(1.15);\n }\n}\n\n.login-corner {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 3;\n display: flex;\n gap: 8px;\n animation: fadeIn 0.9s var(--rise) 0.7s both;\n}\n\n/* 双栏左栏:文字直接压在色场上(像 macOS 桌面上的字),不单独做一块彩色面板 */\n.login-brand {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 48px clamp(32px, 5vw, 76px);\n}\n.login-brand-inner {\n max-width: 440px;\n}\n\n.login-card {\n width: 400px;\n max-width: 100%;\n position: relative;\n z-index: 2;\n margin-top: 44px;\n}\n.login-card.on-desk {\n width: 384px;\n}\n\n/* 表单是一块浮在色场上的毛玻璃卡(macOS 的 vibrancy 材质),单栏双栏同一套 */\n.desk-card {\n border: 1px solid var(--glass-border) !important;\n border-radius: 22px !important;\n background: var(--glass-panel) !important;\n box-shadow: var(--glass-shadow) !important;\n backdrop-filter: blur(40px) saturate(180%);\n -webkit-backdrop-filter: blur(40px) saturate(180%);\n /* 反向视差:卡朝指针方向挪,色场反方向挪,拉出前后景深。\n 卡的跟随比色场快(0.45s 对 1.2s),指针一动卡就有回应;位移在窗口边缘最大,\n 指针停在卡片上时趋近于零,不会让要点的按钮在手下漂走 */\n translate: calc(var(--px, 0) * 16px) calc(var(--py, 0) * 11px);\n transition:\n translate 0.45s var(--rise),\n background-color 0.3s,\n border-color 0.3s,\n box-shadow 0.3s;\n isolation: isolate;\n}\n/* 跟着指针走的柔光:画在毛玻璃面上、内容的下面(isolation + z-index:-1),强调色推导,亮暗主题通用。\n 指针不在窗口内时淡出;--mx / --my 是指针相对卡片左上角的位置(见脚本) */\n.desk-card::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n border-radius: inherit;\n pointer-events: none;\n background: radial-gradient(\n 340px circle at var(--mx, 50%) var(--my, 0%),\n color-mix(in srgb, var(--signal) var(--spot, 28%), transparent),\n transparent 72%\n );\n opacity: var(--lit, 0);\n transition: opacity 0.5s var(--rise);\n}\n/* 亮色的玻璃底本来就亮,同样的强调色占比要给高一点才看得出;暗色里 20% 已经够醒目 */\n:root[data-theme='dark'] .desk-card {\n --spot: 20%;\n}\n.login-card :deep(.n-input) {\n border-radius: var(--radius-md);\n}\n/* 主按钮:强调色 → 第二色渐变,带一层强调色辉光;hover 只加深辉光并微提亮、不位移,按下轻轻收一下 */\n.login-card :deep(.n-button.cta) {\n background-image: linear-gradient(120deg, var(--signal), var(--login-accent-2));\n border-color: transparent;\n box-shadow: 0 10px 26px -10px var(--signal-glow);\n transition:\n box-shadow 0.22s var(--ease),\n transform 0.2s var(--ease),\n filter 0.2s var(--ease);\n}\n.login-card :deep(.n-button.cta:hover) {\n box-shadow: 0 16px 34px -10px var(--signal-glow);\n filter: brightness(1.04);\n}\n.login-card :deep(.n-button.cta:active:not(:disabled)) {\n transform: scale(0.985);\n filter: brightness(0.97);\n box-shadow: 0 6px 18px -10px var(--signal-glow);\n}\n\n/* ── 入场编排 ─────────────────────────────────────────────\n 动画必须挂在 .desk-card 自己身上,不能挂它的父级 .login-card:父级 opacity < 1 会让子元素的\n backdrop-filter 失去背景,动画期间卡是不模糊的,结束那一帧模糊才「啪」地打上去,看着就是生硬。\n 内容项(标题 / 字段 / 按钮 / 左栏文字)各自带延迟依次浮现,先模糊后清晰,不回弹。 */\n.desk-card {\n animation: cardIn 0.95s var(--rise) 0.08s both;\n}\n.login-card > :deep(:not(.desk-card)) {\n animation: fadeIn 0.9s var(--rise) 0.55s both;\n}\n\n/* 左栏:Logo → 标语 → 说明 → 亮点逐行 */\n.login-brand-inner :deep(.login-hero-panel > :not(.points)),\n.login-brand-inner :deep(.points li) {\n animation: riseIn 0.9s var(--rise) both;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(1)) {\n animation-delay: 0.1s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(2)) {\n animation-delay: 0.18s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(3)) {\n animation-delay: 0.26s;\n}\n.login-brand-inner :deep(.points li:nth-child(1)) {\n animation-delay: 0.36s;\n}\n.login-brand-inner :deep(.points li:nth-child(2)) {\n animation-delay: 0.43s;\n}\n.login-brand-inner :deep(.points li:nth-child(n + 3)) {\n animation-delay: 0.5s;\n}\n\n/* 卡内:LoginForm 的 .login-form > .lf-brand / .lf-body(标题、表单、第三方登录)和表单里的各行 */\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert),\n.login-card :deep(.lf-body > :not(form)),\n.login-card :deep(.lf-body form > *) {\n animation: riseIn 0.8s var(--rise) both;\n}\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert) {\n animation-delay: 0.18s;\n}\n.login-card :deep(.lf-body > :not(form)) {\n animation-delay: 0.22s;\n}\n.login-card :deep(.lf-body form > :nth-child(1)) {\n animation-delay: 0.28s;\n}\n.login-card :deep(.lf-body form > :nth-child(2)) {\n animation-delay: 0.34s;\n}\n.login-card :deep(.lf-body form > :nth-child(3)) {\n animation-delay: 0.4s;\n}\n.login-card :deep(.lf-body form > :nth-child(4)) {\n animation-delay: 0.46s;\n}\n.login-card :deep(.lf-body form > :nth-child(n + 5)) {\n animation-delay: 0.52s;\n}\n.login-card :deep(.lf-body > .lf-divider) {\n animation-delay: 0.56s;\n}\n.login-card :deep(.lf-body > .lf-sso) {\n animation-delay: 0.62s;\n}\n\n@keyframes cardIn {\n from {\n opacity: 0;\n transform: translate3d(0, 28px, 0) scale(0.965);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n@keyframes riseIn {\n from {\n opacity: 0;\n transform: translate3d(0, 12px, 0);\n filter: blur(6px);\n }\n to {\n opacity: 1;\n transform: none;\n filter: none;\n }\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ── 退场:登录成功后整页淡出并微微放大(macOS 解锁的感觉),色场留着不动 ── */\n.login.leaving .desk-card {\n animation: cardOut 0.34s cubic-bezier(0.4, 0, 1, 1) both;\n}\n.login.leaving .login-brand-inner,\n.login.leaving .login-corner,\n.login.leaving .login-card > :deep(:not(.desk-card)) {\n animation: fadeOut 0.28s ease-in both;\n}\n@keyframes cardOut {\n to {\n opacity: 0;\n transform: translate3d(0, -8px, 0) scale(1.02);\n }\n}\n@keyframes fadeOut {\n to {\n opacity: 0;\n }\n}\n\n/* 减少动效:全局规则已把时长压到近零,这里再清掉延迟(否则 both 的起始态会把内容藏到延迟结束)并取消视差与漂移 */\n@media (prefers-reduced-motion: reduce) {\n .desk i {\n animation: none !important;\n }\n .desk,\n .desk-card {\n translate: none;\n }\n .desk-card::after {\n display: none;\n }\n .login :deep(*),\n .login .desk-card,\n .login .login-corner {\n animation-delay: 0s !important;\n }\n}\n/* 窄屏收紧:卡片侧边留 16px,卡内边距随之压小(内联的 content-style 要靠 !important 盖住) */\n@media (max-width: 480px) {\n .login-stage {\n padding: 16px;\n }\n .desk-card :deep(.n-card__content) {\n padding: 22px 20px 18px !important;\n }\n}\n</style>\n\n<!-- View Transitions 的伪元素在文档根上,scoped 样式够不到,所以单独一块全局样式。\n 只在布局切换那一刻(.switching)给卡片命名:常驻的 view-transition-name 会让它多出独立图层。 -->\n<style>\n.login.switching .desk-card {\n view-transition-name: login-card;\n}\n::view-transition-group(login-card) {\n animation-duration: 0.62s;\n animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);\n}\n</style>\n"],"names":["app","useAppStore","t","useI18n","root","ref","raf","setPointer","x","y","clientX","clientY","el","card","_a","onPointerMove","onBeforeUnmount","_createElementBlock","_normalizeClass","__props","_createElementVNode","_openBlock","_hoisted_1","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_hoisted_4","_createVNode","_unref","NTooltip","NButton","_cache","$event","Icon","_createTextVNode","_normalizeStyle","NCard"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LoginDesk2.vue.js","sources":["../../../../src/views/login/components/LoginDesk.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 入口类全屏页(登录 / 二次验证 / 第三方回调 / 门户加载失败)共用的外壳:macOS 锁屏语言。\n// 整页一张慢慢飘的柔光色场(.desk,颜色全由强调色推导,无网格)+ 浮在上面的毛玻璃卡,右上角是工具栏。\n// 单栏 = 居中一张卡;双栏(split)= 左栏品牌区(brand 插槽)压在色场上,右栏是这张卡。\n// 只管视觉外壳:卡里放什么、表单怎么提交都在各页自己手里。\n//\n// 动效(全部不回弹):入场按「卡 → 标题 → 字段 → 按钮」依次浮现(先模糊后清晰);\n// 色场与卡跟着指针做反向视差;leaving 为真时整页淡出放大一点(像 macOS 解锁),给登录成功收尾。\nimport { onBeforeUnmount, ref } from 'vue'\nimport { NButton, NCard, NTooltip } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useAppStore } from '#/stores/app'\n\nwithDefaults(\n defineProps<{\n /** 双栏:左栏渲染 brand 插槽,卡片宽度收到 384 */\n split?: boolean\n /** 卡片宽度(px),窄屏被 max-width:100% 收住 */\n width?: number\n /** NCard 内容区内边距 */\n contentStyle?: string\n /** 退场:登录成功后由页面置真,整页淡出,等动画播完再跳转 */\n leaving?: boolean\n }>(),\n { split: false, width: 400, contentStyle: 'padding: 26px 26px 22px', leaving: false },\n)\n\nconst app = useAppStore()\nconst { t } = useI18n()\n\n// 指针视差:只认鼠标(触屏没有悬停位置),坐标归一到 -1..1 写成 CSS 变量,位移与过渡都在 CSS 里。\n// 另外把指针相对卡片左上角的位置(--mx / --my,px)和「指针在窗口内」(--lit)写出来,\n// 给卡片面上那束跟着指针走的柔光用:指针停在卡片上时视差位移趋近于零,光斑是这时唯一的反馈。\nconst root = ref<HTMLElement | null>(null)\nlet raf = 0\nfunction setPointer(x: number, y: number, clientX?: number, clientY?: number) {\n cancelAnimationFrame(raf)\n raf = requestAnimationFrame(() => {\n const el = root.value\n if (!el) return\n el.style.setProperty('--px', x.toFixed(3))\n el.style.setProperty('--py', y.toFixed(3))\n if (clientX === undefined || clientY === undefined) {\n // 指针离开:只熄灭柔光,保留最后位置,淡出时光斑不跳\n el.style.setProperty('--lit', '0')\n return\n }\n const card = el.querySelector('.desk-card')?.getBoundingClientRect()\n if (card) {\n el.style.setProperty('--mx', `${(clientX - card.left).toFixed(1)}px`)\n el.style.setProperty('--my', `${(clientY - card.top).toFixed(1)}px`)\n }\n el.style.setProperty('--lit', '1')\n })\n}\nfunction onPointerMove(e: PointerEvent) {\n if (e.pointerType !== 'mouse') return\n setPointer(\n (e.clientX / window.innerWidth) * 2 - 1,\n (e.clientY / window.innerHeight) * 2 - 1,\n e.clientX,\n e.clientY,\n )\n}\nonBeforeUnmount(() => cancelAnimationFrame(raf))\n</script>\n\n<template>\n <div\n ref=\"root\"\n class=\"login desk-bg\"\n :class=\"{ split, leaving }\"\n @pointermove=\"onPointerMove\"\n @pointerleave=\"setPointer(0, 0)\"\n >\n <div class=\"desk\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n <i />\n </div>\n\n <div v-if=\"split\" class=\"login-brand\">\n <div class=\"login-brand-inner\"><slot name=\"brand\" /></div>\n </div>\n\n <div class=\"login-stage\">\n <!-- 右上角工具栏:页面自己的按钮(布局切换、语言)在前,主题切换永远贴最右角 -->\n <div class=\"login-corner\">\n <slot name=\"corner\" />\n <n-tooltip>\n <template #trigger>\n <n-button\n quaternary\n circle\n :aria-label=\"app.isDark ? t('app.light') : t('app.dark')\"\n @click=\"app.toggleDark()\"\n >\n <template #icon>\n <Icon :icon=\"app.isDark ? 'ph:moon' : 'ph:sun'\" :width=\"18\" />\n </template>\n </n-button>\n </template>\n {{ app.isDark ? t('app.light') : t('app.dark') }}\n </n-tooltip>\n </div>\n\n <!-- margin-top 给右上角工具栏留位:窄屏内容比视口高时,顶部不会被工具栏盖住 -->\n <div\n class=\"login-card\"\n :class=\"{ 'on-desk': split }\"\n :style=\"split ? undefined : { width: `${width}px` }\"\n >\n <slot name=\"above\" />\n <n-card :bordered=\"true\" class=\"desk-card\" :content-style=\"contentStyle\">\n <slot />\n </n-card>\n <slot name=\"after\" />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n/* 登录页(单栏 / 双栏都算)是 macOS 桌面那种纯色场:不要网格线,不要透视地面 */\n.login {\n /* 减速到底、不过冲:入场与视差共用这条曲线 */\n --rise: cubic-bezier(0.22, 1, 0.36, 1);\n min-height: 100dvh;\n background: var(--desk-base);\n position: relative;\n overflow: hidden;\n}\n.login.split {\n display: grid;\n grid-template-columns: minmax(340px, 46%) 1fr;\n}\n.login-stage {\n min-height: 100dvh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n position: relative;\n overflow: hidden;\n}\n\n/* 色场:四团 blur(70px) 的柔光球慢速漂移,颜色由强调色推导(--desk-1..4);\n 整体再按指针反向平移一点(用独立的 translate 属性,不和漂移动画的 transform 打架) */\n.desk {\n position: absolute;\n inset: -20%;\n pointer-events: none;\n z-index: 0;\n translate: calc(var(--px, 0) * -44px) calc(var(--py, 0) * -30px);\n transition: translate 1.2s var(--rise);\n}\n.desk i {\n position: absolute;\n display: block;\n border-radius: 50%;\n filter: blur(70px);\n opacity: var(--desk-op);\n}\n.desk i:nth-child(1) {\n left: 2%;\n top: 4%;\n width: 46%;\n height: 62%;\n background: var(--desk-1);\n animation: drift1 26s ease-in-out infinite alternate;\n}\n.desk i:nth-child(2) {\n left: 26%;\n top: 34%;\n width: 44%;\n height: 56%;\n background: var(--desk-2);\n animation: drift2 32s ease-in-out infinite alternate;\n}\n.desk i:nth-child(3) {\n left: 54%;\n top: -6%;\n width: 40%;\n height: 58%;\n background: var(--desk-3);\n animation: drift3 29s ease-in-out infinite alternate;\n}\n.desk i:nth-child(4) {\n left: 62%;\n top: 46%;\n width: 46%;\n height: 62%;\n background: var(--desk-4);\n animation: drift1 35s ease-in-out infinite alternate-reverse;\n}\n@keyframes drift1 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(6%, -5%, 0) scale(1.12);\n }\n}\n@keyframes drift2 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(-7%, 4%, 0) scale(1.08);\n }\n}\n@keyframes drift3 {\n from {\n transform: none;\n }\n to {\n transform: translate3d(4%, 7%, 0) scale(1.15);\n }\n}\n\n.login-corner {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 3;\n display: flex;\n gap: 8px;\n animation: fadeIn 0.9s var(--rise) 0.7s both;\n}\n\n/* 双栏左栏:文字直接压在色场上(像 macOS 桌面上的字),不单独做一块彩色面板 */\n.login-brand {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding: 48px clamp(32px, 5vw, 76px);\n}\n.login-brand-inner {\n max-width: 440px;\n}\n\n.login-card {\n width: 400px;\n max-width: 100%;\n position: relative;\n z-index: 2;\n margin-top: 44px;\n}\n.login-card.on-desk {\n width: 384px;\n}\n\n/* 表单是一块浮在色场上的毛玻璃卡(macOS 的 vibrancy 材质),单栏双栏同一套 */\n.desk-card {\n border: 1px solid var(--glass-border) !important;\n border-radius: 22px !important;\n background: var(--glass-panel) !important;\n box-shadow: var(--glass-shadow) !important;\n backdrop-filter: blur(40px) saturate(180%);\n -webkit-backdrop-filter: blur(40px) saturate(180%);\n /* 反向视差:卡朝指针方向挪,色场反方向挪,拉出前后景深。\n 卡的跟随比色场快(0.45s 对 1.2s),指针一动卡就有回应;位移在窗口边缘最大,\n 指针停在卡片上时趋近于零,不会让要点的按钮在手下漂走 */\n translate: calc(var(--px, 0) * 16px) calc(var(--py, 0) * 11px);\n transition:\n translate 0.45s var(--rise),\n background-color 0.3s,\n border-color 0.3s,\n box-shadow 0.3s;\n isolation: isolate;\n}\n/* 跟着指针走的柔光:画在毛玻璃面上、内容的下面(isolation + z-index:-1),强调色推导,亮暗主题通用。\n 指针不在窗口内时淡出;--mx / --my 是指针相对卡片左上角的位置(见脚本) */\n.desk-card::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n border-radius: inherit;\n pointer-events: none;\n background: radial-gradient(\n 340px circle at var(--mx, 50%) var(--my, 0%),\n color-mix(in srgb, var(--signal) var(--spot, 28%), transparent),\n transparent 72%\n );\n opacity: var(--lit, 0);\n transition: opacity 0.5s var(--rise);\n}\n/* 亮色的玻璃底本来就亮,同样的强调色占比要给高一点才看得出;暗色里 20% 已经够醒目 */\n:root[data-theme='dark'] .desk-card {\n --spot: 20%;\n}\n.login-card :deep(.n-input) {\n border-radius: var(--radius-md);\n}\n/* 主按钮:强调色 → 第二色渐变,带一层强调色辉光;hover 只加深辉光并微提亮、不位移,按下轻轻收一下 */\n.login-card :deep(.n-button.cta) {\n background-image: linear-gradient(120deg, var(--signal), var(--login-accent-2));\n border-color: transparent;\n box-shadow: 0 10px 26px -10px var(--signal-glow);\n transition:\n box-shadow 0.22s var(--ease),\n transform 0.2s var(--ease),\n filter 0.2s var(--ease);\n}\n.login-card :deep(.n-button.cta:hover) {\n box-shadow: 0 16px 34px -10px var(--signal-glow);\n filter: brightness(1.04);\n}\n.login-card :deep(.n-button.cta:active:not(:disabled)) {\n transform: scale(0.985);\n filter: brightness(0.97);\n box-shadow: 0 6px 18px -10px var(--signal-glow);\n}\n\n/* ── 入场编排 ─────────────────────────────────────────────\n 动画必须挂在 .desk-card 自己身上,不能挂它的父级 .login-card:父级 opacity < 1 会让子元素的\n backdrop-filter 失去背景,动画期间卡是不模糊的,结束那一帧模糊才「啪」地打上去,看着就是生硬。\n 内容项(标题 / 字段 / 按钮 / 左栏文字)各自带延迟依次浮现,先模糊后清晰,不回弹。 */\n.desk-card {\n animation: cardIn 0.95s var(--rise) 0.08s both;\n}\n.login-card > :deep(:not(.desk-card)) {\n animation: fadeIn 0.9s var(--rise) 0.55s both;\n}\n\n/* 左栏:Logo → 标语 → 说明 → 亮点逐行 */\n.login-brand-inner :deep(.login-hero-panel > :not(.points)),\n.login-brand-inner :deep(.points li) {\n animation: riseIn 0.9s var(--rise) both;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(1)) {\n animation-delay: 0.1s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(2)) {\n animation-delay: 0.18s;\n}\n.login-brand-inner :deep(.login-hero-panel > :nth-child(3)) {\n animation-delay: 0.26s;\n}\n.login-brand-inner :deep(.points li:nth-child(1)) {\n animation-delay: 0.36s;\n}\n.login-brand-inner :deep(.points li:nth-child(2)) {\n animation-delay: 0.43s;\n}\n.login-brand-inner :deep(.points li:nth-child(n + 3)) {\n animation-delay: 0.5s;\n}\n\n/* 卡内:LoginForm 的 .login-form > .lf-brand / .lf-body(标题、表单、第三方登录)和表单里的各行 */\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert),\n.login-card :deep(.lf-body > :not(form)),\n.login-card :deep(.lf-body form > *) {\n animation: riseIn 0.8s var(--rise) both;\n}\n.login-card :deep(.login-form > .lf-brand),\n.login-card :deep(.login-form > .lf-pending-alert) {\n animation-delay: 0.18s;\n}\n.login-card :deep(.lf-body > :not(form)) {\n animation-delay: 0.22s;\n}\n.login-card :deep(.lf-body form > :nth-child(1)) {\n animation-delay: 0.28s;\n}\n.login-card :deep(.lf-body form > :nth-child(2)) {\n animation-delay: 0.34s;\n}\n.login-card :deep(.lf-body form > :nth-child(3)) {\n animation-delay: 0.4s;\n}\n.login-card :deep(.lf-body form > :nth-child(4)) {\n animation-delay: 0.46s;\n}\n.login-card :deep(.lf-body form > :nth-child(n + 5)) {\n animation-delay: 0.52s;\n}\n.login-card :deep(.lf-body > .lf-divider) {\n animation-delay: 0.56s;\n}\n.login-card :deep(.lf-body > .lf-sso) {\n animation-delay: 0.62s;\n}\n\n@keyframes cardIn {\n from {\n opacity: 0;\n transform: translate3d(0, 28px, 0) scale(0.965);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n@keyframes riseIn {\n from {\n opacity: 0;\n transform: translate3d(0, 12px, 0);\n filter: blur(6px);\n }\n to {\n opacity: 1;\n transform: none;\n filter: none;\n }\n}\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* ── 退场:登录成功后整页淡出并微微放大(macOS 解锁的感觉),色场留着不动 ── */\n.login.leaving .desk-card {\n animation: cardOut 0.34s cubic-bezier(0.4, 0, 1, 1) both;\n}\n.login.leaving .login-brand-inner,\n.login.leaving .login-corner,\n.login.leaving .login-card > :deep(:not(.desk-card)) {\n animation: fadeOut 0.28s ease-in both;\n}\n@keyframes cardOut {\n to {\n opacity: 0;\n transform: translate3d(0, -8px, 0) scale(1.02);\n }\n}\n@keyframes fadeOut {\n to {\n opacity: 0;\n }\n}\n\n/* 减少动效:全局规则已把时长压到近零,这里再清掉延迟(否则 both 的起始态会把内容藏到延迟结束)并取消色场漂移。\n 指针视差与柔光不跟随这个偏好:Windows 关了「动画效果」、远程桌面、省电模式下浏览器都会报 reduce,\n 而它们是这页唯一的鼠标反馈。全局规则会把它们的 transition 压成 0.01ms(位移变瞬跳),\n 所以把缓动时长还回去;卡片的颜色 / 边框 / 阴影三项仍按全局规则保持瞬时。 */\n@media (prefers-reduced-motion: reduce) {\n .desk i {\n animation: none !important;\n }\n .desk {\n transition-duration: 1.2s !important;\n }\n .desk-card {\n transition-duration: 0.45s, 0.01ms, 0.01ms, 0.01ms !important;\n }\n .desk-card::after {\n transition-duration: 0.5s !important;\n }\n .login :deep(*),\n .login .desk-card,\n .login .login-corner {\n animation-delay: 0s !important;\n }\n}\n/* 窄屏收紧:卡片侧边留 16px,卡内边距随之压小(内联的 content-style 要靠 !important 盖住) */\n@media (max-width: 480px) {\n .login-stage {\n padding: 16px;\n }\n .desk-card :deep(.n-card__content) {\n padding: 22px 20px 18px !important;\n }\n}\n</style>\n\n<!-- View Transitions 的伪元素在文档根上,scoped 样式够不到,所以单独一块全局样式。\n 只在布局切换那一刻(.switching)给卡片命名:常驻的 view-transition-name 会让它多出独立图层。 -->\n<style>\n.login.switching .desk-card {\n view-transition-name: login-card;\n}\n::view-transition-group(login-card) {\n animation-duration: 0.62s;\n animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);\n}\n</style>\n"],"names":["app","useAppStore","t","useI18n","root","ref","raf","setPointer","x","y","clientX","clientY","el","card","_a","onPointerMove","onBeforeUnmount","_createElementBlock","_normalizeClass","__props","_createElementVNode","_openBlock","_hoisted_1","_hoisted_2","_renderSlot","_ctx","_hoisted_3","_hoisted_4","_createVNode","_unref","NTooltip","NButton","_cache","$event","Icon","_createTextVNode","_normalizeStyle","NCard"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import o from "./LoginHeroPanel2.vue.js";
|
|
2
2
|
/* empty css */
|
|
3
|
-
import
|
|
4
|
-
const m = /* @__PURE__ */
|
|
3
|
+
import e from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
+
const m = /* @__PURE__ */ e(o, [["__scopeId", "data-v-38ce8a2e"]]);
|
|
5
5
|
export {
|
|
6
6
|
m as default
|
|
7
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginHeroPanel2.vue.js","sources":["../../../../src/views/login/components/LoginHeroPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 登录页双栏左栏的品牌区(也是配置中心登录预览的左半边):文字直接压在柔光色场上,\n// Logo 锁定 + 大标语(强调词用强调色渐变高亮)+ 一行说明 + 单行勾选亮点。\nimport { computed } from 'vue'\nimport { Icon } from '@iconify/vue'\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 { 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=\"46\" :src=\"logo\" />\n <span>{{ title ?? site.title }}</span>\n </div>\n <h2 class=\"headline\">\n <span\n v-for=\"(part, index) in headlineParts\"\n :key=\"index\"\n :class=\"{ hl: part.accent }\"\n v-text=\"part.text\"\n />\n </h2>\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\" :width=\"15\" />\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: 13px;\n margin-bottom: 30px;\n font-size:
|
|
1
|
+
{"version":3,"file":"LoginHeroPanel2.vue.js","sources":["../../../../src/views/login/components/LoginHeroPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 登录页双栏左栏的品牌区(也是配置中心登录预览的左半边):文字直接压在柔光色场上,\n// Logo 锁定 + 大标语(强调词用强调色渐变高亮)+ 一行说明 + 单行勾选亮点。\nimport { computed } from 'vue'\nimport { Icon } from '@iconify/vue'\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 { 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=\"46\" :src=\"logo\" />\n <span>{{ title ?? site.title }}</span>\n </div>\n <h2 class=\"headline\">\n <span\n v-for=\"(part, index) in headlineParts\"\n :key=\"index\"\n :class=\"{ hl: part.accent }\"\n v-text=\"part.text\"\n />\n </h2>\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\" :width=\"15\" />\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: 13px;\n margin-bottom: 30px;\n font-size: 28px;\n font-weight: 600;\n letter-spacing: -0.015em;\n color: var(--text-1);\n}\n.headline {\n margin: 0 0 14px;\n color: var(--text-1);\n font-size: clamp(30px, 2.5vw, 40px);\n font-weight: 600;\n letter-spacing: -0.04em;\n line-height: 1.18;\n}\n.headline .hl {\n background: linear-gradient(110deg, var(--signal), var(--login-accent-2));\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n/* 色场上的正文一律用 --text-1:--text-2 是配白底卡片的,直接压在饱和色场上对比度不够 */\n.sub {\n margin: 0 0 34px;\n color: var(--text-1);\n font-size: 17px;\n line-height: 1.6;\n}\n.points {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n/* 字重 500 + 16px:同样是 --text-1,靠字重和字号把亮点和上面那句说明分开,不靠深浅 */\n.points li {\n display: flex;\n align-items: center;\n gap: 12px;\n color: var(--text-1);\n font-size: 16px;\n font-weight: 500;\n}\n.points li > :deep(svg) {\n flex-shrink: 0;\n box-sizing: content-box;\n width: 15px;\n height: 15px;\n padding: 5px;\n border-radius: 50%;\n color: var(--signal);\n background: var(--sel-bg);\n box-shadow: inset 0 0 0 1px var(--sel-ring);\n}\n</style>\n"],"names":["props","__props","site","useSite","headlineParts","computed","index","part","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","SmartLogo","_toDisplayString","_unref","_hoisted_3","_Fragment","_renderList","_normalizeClass","_hoisted_5","_hoisted_6","feature","Icon","_createTextVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAMA,IAAQC,GAmBR,EAAE,MAAAC,EAAA,IAASC,EAAA,GAGXC,IAAgBC,EAAS,MAAM;AACnC,YAAMC,IAAQN,EAAM,YAAYA,EAAM,SAAS,QAAQA,EAAM,SAAS,IAAI;AAC1E,aAAIM,IAAQ,IAAU,CAAC,EAAE,MAAMN,EAAM,UAAU,QAAQ,IAAO,IACvD;AAAA,QACL,EAAE,MAAMA,EAAM,SAAS,MAAM,GAAGM,CAAK,GAAG,QAAQ,GAAA;AAAA,QAChD,EAAE,MAAMN,EAAM,WAAW,QAAQ,GAAA;AAAA,QACjC,EAAE,MAAMA,EAAM,SAAS,MAAMM,IAAQN,EAAM,UAAU,MAAM,GAAG,QAAQ,GAAA;AAAA,MAAM,EAC5E,OAAO,CAAAO,MAAQA,EAAK,IAAI;AAAA,IAC5B,CAAC;sBAICC,EAAA,GAAAC,EAoBM,OApBNC,GAoBM;AAAA,MAnBJC,EAGM,OAHNC,GAGM;AAAA,QAFJC,EAAoCC,GAAA;AAAA,UAAxB,MAAM;AAAA,UAAK,KAAKb,EAAA;AAAA,QAAA;QAC5BU,EAAsC,QAAA,MAAAI,EAA7Bd,EAAA,SAASe,EAAAd,CAAA,EAAK,KAAK,GAAA,CAAA;AAAA,MAAA;MAE9BS,EAOK,MAPLM,GAOK;AAAA,SANHT,EAAA,EAAA,GAAAC,EAKES,GAAA,MAAAC,EAJwBf,EAAA,OAAa,CAA7BG,GAAMD,YADhBG,EAKE,QAAA;AAAA,UAHC,KAAKH;AAAA,UACL,OAAKc,EAAA,EAAA,IAAQb,EAAK,QAAM;AAAA,uBACzBQ,EAAkBR,EAAL,IAAI;AAAA,QAAA;;MAGZN,EAAA,iBAATQ,EAAiD,KAAjDY,GAAiDN,EAAfd,EAAA,QAAQ,GAAA,CAAA;MAChCA,EAAA,SAAS,UAAnBO,KAAAC,EAKK,MALLa,GAKK;AAAA,gBAJHb,EAGKS,GAAA,MAAAC,EAHiBlB,EAAA,UAAQ,CAAnBsB,YAAXd,EAGK,MAAA,EAH4B,KAAKc,KAAO;AAAA,UAC3CV,EAAoCG,EAAAQ,CAAA,GAAA;AAAA,YAA9B,MAAK;AAAA,YAAY,OAAO;AAAA,UAAA;UAAMC,EAAA,QACjCF,CAAO,GAAA,CAAA;AAAA,QAAA;;;;;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import o from "./index2.vue.js";
|
|
2
2
|
/* empty css */
|
|
3
3
|
import t from "../../../_virtual/_plugin-vue_export-helper.js";
|
|
4
|
-
const
|
|
4
|
+
const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-c532e04a"]]);
|
|
5
5
|
export {
|
|
6
|
-
|
|
6
|
+
m as default
|
|
7
7
|
};
|
|
8
8
|
//# sourceMappingURL=index.vue.js.map
|