openxiangda 1.0.68 → 1.0.70
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/package.json +1 -1
- package/templates/openxiangda-react-spa/AGENTS.md +26 -19
- package/templates/openxiangda-react-spa/src/app/navigation.ts +165 -0
- package/templates/openxiangda-react-spa/src/app/router.tsx +20 -62
- package/templates/openxiangda-react-spa/src/app/starter-content.ts +182 -0
- package/templates/openxiangda-react-spa/src/layouts/AdminShell.tsx +94 -233
- package/templates/openxiangda-react-spa/src/layouts/PublicShell.tsx +6 -6
- package/templates/openxiangda-react-spa/src/layouts/UserShell.tsx +15 -15
- package/templates/openxiangda-react-spa/src/pages/admin/AdminDashboardPage.tsx +193 -0
- package/templates/openxiangda-react-spa/src/pages/admin/DataCenterPage.tsx +96 -0
- package/templates/openxiangda-react-spa/src/pages/admin/ServiceCenterPage.tsx +100 -0
- package/templates/openxiangda-react-spa/src/pages/admin/TaskCenterPage.tsx +135 -0
- package/templates/openxiangda-react-spa/src/pages/defaults/DataRoutePage.tsx +22 -25
- package/templates/openxiangda-react-spa/src/pages/defaults/FilePreviewRoutePage.tsx +41 -45
- package/templates/openxiangda-react-spa/src/pages/defaults/FormRoutePage.tsx +22 -30
- package/templates/openxiangda-react-spa/src/pages/portal/UserPortalPage.tsx +47 -42
- package/templates/openxiangda-react-spa/src/pages/public/PublicHomePage.tsx +30 -31
- package/templates/openxiangda-react-spa/src/pages/states/NotFoundPage.tsx +7 -7
- package/templates/openxiangda-react-spa/src/resources/menus/menus.json +32 -5
- package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-admin.json +17 -3
- package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-user.json +1 -1
- package/templates/openxiangda-react-spa/src/resources/roles/roles.json +2 -2
- package/templates/openxiangda-react-spa/src/shared/mac-admin.tsx +2 -2
- package/templates/openxiangda-react-spa/src/shared/ui.tsx +13 -0
- package/templates/openxiangda-react-spa/src/pages/admin/RuntimeWorkspacePage.tsx +0 -219
|
@@ -1,58 +1,68 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExternalLink, LockKeyhole, ShieldCheck } from "lucide-react";
|
|
2
2
|
import { useParams } from "react-router-dom";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
MacDiagnosticPanel,
|
|
6
|
-
MacPageHeader,
|
|
7
|
-
MacPanel,
|
|
8
|
-
MacStatePage,
|
|
9
|
-
MacStatusPill,
|
|
10
|
-
} from "@/shared/mac-admin";
|
|
11
4
|
import {
|
|
12
5
|
defaultPageOverrides,
|
|
13
6
|
resolveDefaultPageOverride,
|
|
14
7
|
} from "@/runtime/default-page-overrides";
|
|
8
|
+
import {
|
|
9
|
+
PageHeader,
|
|
10
|
+
Panel,
|
|
11
|
+
PrimaryButton,
|
|
12
|
+
StatePage,
|
|
13
|
+
StatusPill,
|
|
14
|
+
} from "@/shared/ui";
|
|
15
|
+
|
|
16
|
+
const servicePrefix = process.env.APP_SERVICE_PREFIX || "/service";
|
|
15
17
|
|
|
16
18
|
export function FilePreviewRoutePage() {
|
|
17
19
|
const params = useParams();
|
|
18
20
|
const ticket = new URLSearchParams(window.location.search).get("ticket") || "";
|
|
19
21
|
const appType = params.appType || process.env.OPENXIANGDA_APP_TYPE || process.env.APP_TYPE || "";
|
|
20
22
|
const Override = resolveDefaultPageOverride(defaultPageOverrides, "file-preview");
|
|
23
|
+
const previewUrl = ticket
|
|
24
|
+
? `${servicePrefix.replace(/\/+$/, "")}/file/preview-by-ticket/${encodeURIComponent(ticket)}`
|
|
25
|
+
: "";
|
|
26
|
+
|
|
21
27
|
const defaultNode = ticket ? (
|
|
22
28
|
<div className="min-w-0 space-y-5">
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
<PageHeader
|
|
30
|
+
actions={
|
|
31
|
+
<PrimaryButton onClick={() => window.open(previewUrl, "_blank", "noopener,noreferrer")}>
|
|
32
|
+
<ExternalLink size={17} />
|
|
33
|
+
新窗口打开
|
|
34
|
+
</PrimaryButton>
|
|
35
|
+
}
|
|
36
|
+
description="通过安全链接打开文件内容。若浏览器无法直接预览,可在新窗口中打开或下载。"
|
|
26
37
|
meta={
|
|
27
38
|
<>
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
<MacStatusPill tone="amber">可 override</MacStatusPill>
|
|
39
|
+
<StatusPill tone="blue">文件预览</StatusPill>
|
|
40
|
+
<StatusPill tone="emerald">安全访问</StatusPill>
|
|
31
41
|
</>
|
|
32
42
|
}
|
|
33
43
|
title="文件预览"
|
|
34
44
|
/>
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<Info label="appType" value={appType || "--"} />
|
|
43
|
-
<Info label="preview" value="waiting for file metadata API" />
|
|
44
|
-
</div>
|
|
45
|
-
</div>
|
|
46
|
-
</MacPanel>
|
|
47
|
-
<MacDiagnosticPanel data={{ appType, ticket, kind: "file-preview" }} title="文件预览上下文" />
|
|
45
|
+
<Panel className="min-h-[70vh] overflow-hidden p-0">
|
|
46
|
+
<iframe
|
|
47
|
+
className="min-h-[70vh] w-full border-0 bg-white"
|
|
48
|
+
src={previewUrl}
|
|
49
|
+
title="文件预览"
|
|
50
|
+
/>
|
|
51
|
+
</Panel>
|
|
48
52
|
</div>
|
|
49
53
|
) : (
|
|
50
|
-
<
|
|
51
|
-
|
|
54
|
+
<StatePage
|
|
55
|
+
actions={
|
|
56
|
+
<PrimaryButton onClick={() => window.history.back()}>
|
|
57
|
+
<ShieldCheck size={17} />
|
|
58
|
+
返回上一页
|
|
59
|
+
</PrimaryButton>
|
|
60
|
+
}
|
|
61
|
+
description="当前链接已失效或缺少必要的访问凭证。请从业务页面重新打开文件。"
|
|
52
62
|
fullScreen
|
|
53
63
|
icon={<LockKeyhole size={24} />}
|
|
54
|
-
status="
|
|
55
|
-
title="
|
|
64
|
+
status="INVALID"
|
|
65
|
+
title="文件链接不可用"
|
|
56
66
|
/>
|
|
57
67
|
);
|
|
58
68
|
|
|
@@ -68,17 +78,3 @@ export function FilePreviewRoutePage() {
|
|
|
68
78
|
</main>
|
|
69
79
|
);
|
|
70
80
|
}
|
|
71
|
-
|
|
72
|
-
function Info({ label, value }: { label: string; value: string }) {
|
|
73
|
-
return (
|
|
74
|
-
<div className="flex min-w-0 items-center gap-3 rounded-2xl bg-slate-50 px-4 py-3">
|
|
75
|
-
<span className="grid h-9 w-9 shrink-0 place-items-center rounded-xl bg-blue-50 text-blue-700">
|
|
76
|
-
{label === "ticket" ? <Ticket size={17} /> : <ShieldCheck size={17} />}
|
|
77
|
-
</span>
|
|
78
|
-
<span className="min-w-0">
|
|
79
|
-
<span className="block text-xs font-medium text-slate-500">{label}</span>
|
|
80
|
-
<span className="block truncate text-sm font-semibold text-slate-950">{value}</span>
|
|
81
|
-
</span>
|
|
82
|
-
</div>
|
|
83
|
-
);
|
|
84
|
-
}
|
|
@@ -6,13 +6,12 @@ import { normalizeRuntimeFormSchema } from "openxiangda/runtime";
|
|
|
6
6
|
import { useOpenXiangda, useRuntimeAuth } from "openxiangda/runtime/react";
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "@/shared/mac-admin";
|
|
9
|
+
PageHeader,
|
|
10
|
+
Panel,
|
|
11
|
+
PrimaryButton,
|
|
12
|
+
StatePage,
|
|
13
|
+
StatusPill,
|
|
14
|
+
} from "@/shared/ui";
|
|
16
15
|
import {
|
|
17
16
|
defaultPageOverrides,
|
|
18
17
|
resolveDefaultPageOverride,
|
|
@@ -90,7 +89,7 @@ export function FormRoutePage({ mode }: { mode: Mode }) {
|
|
|
90
89
|
const pageCopy = useMemo(() => resolvePageCopy(overrideKind, mode), [mode, overrideKind]);
|
|
91
90
|
|
|
92
91
|
if (error) return <DefaultErrorState error={error} />;
|
|
93
|
-
if (!schema) return <DefaultLoadingState description="
|
|
92
|
+
if (!schema) return <DefaultLoadingState description="正在读取页面配置和当前用户权限。" title="正在加载" />;
|
|
94
93
|
|
|
95
94
|
const Override = resolveDefaultPageOverride(defaultPageOverrides, overrideKind, formUuid);
|
|
96
95
|
const defaultNode = (
|
|
@@ -112,19 +111,17 @@ export function FormRoutePage({ mode }: { mode: Mode }) {
|
|
|
112
111
|
|
|
113
112
|
return (
|
|
114
113
|
<div className="min-w-0 space-y-5">
|
|
115
|
-
<
|
|
114
|
+
<PageHeader
|
|
116
115
|
description={pageCopy.description}
|
|
117
|
-
eyebrow={pageCopy.eyebrow}
|
|
118
116
|
meta={
|
|
119
117
|
<>
|
|
120
|
-
<
|
|
121
|
-
<
|
|
122
|
-
<MacStatusPill tone="violet">override ready</MacStatusPill>
|
|
118
|
+
<StatusPill tone={isProcessForm ? "amber" : "blue"}>{isProcessForm ? "流程办理" : "业务申请"}</StatusPill>
|
|
119
|
+
<StatusPill tone="emerald">权限已校验</StatusPill>
|
|
123
120
|
</>
|
|
124
121
|
}
|
|
125
122
|
title={pageCopy.title}
|
|
126
123
|
/>
|
|
127
|
-
<
|
|
124
|
+
<Panel className="min-w-0 overflow-hidden">
|
|
128
125
|
{Override ? (
|
|
129
126
|
<Override
|
|
130
127
|
appType={appType}
|
|
@@ -137,15 +134,14 @@ export function FormRoutePage({ mode }: { mode: Mode }) {
|
|
|
137
134
|
) : (
|
|
138
135
|
defaultNode
|
|
139
136
|
)}
|
|
140
|
-
</
|
|
141
|
-
<MacDiagnosticPanel data={{ appType, formInstId, formUuid, kind: overrideKind }} title="默认页上下文" />
|
|
137
|
+
</Panel>
|
|
142
138
|
</div>
|
|
143
139
|
);
|
|
144
140
|
}
|
|
145
141
|
|
|
146
142
|
function DefaultLoadingState({ description, title }: { description: string; title: string }) {
|
|
147
143
|
return (
|
|
148
|
-
<
|
|
144
|
+
<StatePage
|
|
149
145
|
description={description}
|
|
150
146
|
icon={<FileText size={24} />}
|
|
151
147
|
status="LOADING"
|
|
@@ -165,8 +161,8 @@ function DefaultErrorState({ error }: { error: PageError }) {
|
|
|
165
161
|
|
|
166
162
|
if (error.type === "unauthenticated") {
|
|
167
163
|
return (
|
|
168
|
-
<
|
|
169
|
-
actions={<
|
|
164
|
+
<StatePage
|
|
165
|
+
actions={<PrimaryButton onClick={() => void auth.redirectToLogin({ replace: true })}>去登录</PrimaryButton>}
|
|
170
166
|
description="当前没有有效登录态,正在跳转到登录页。"
|
|
171
167
|
icon={<LogIn size={24} />}
|
|
172
168
|
status="401"
|
|
@@ -176,11 +172,11 @@ function DefaultErrorState({ error }: { error: PageError }) {
|
|
|
176
172
|
}
|
|
177
173
|
|
|
178
174
|
return (
|
|
179
|
-
<
|
|
175
|
+
<StatePage
|
|
180
176
|
description={error.message || "请确认当前用户是否拥有表单、流程或数据访问权限。"}
|
|
181
177
|
icon={error.type === "forbidden" ? <Shield size={24} /> : <Workflow size={24} />}
|
|
182
178
|
status={error.type === "forbidden" ? "403" : String(error.status || "ERROR")}
|
|
183
|
-
title={error.type === "forbidden" ? "
|
|
179
|
+
title={error.type === "forbidden" ? "无权访问当前页面" : "页面加载失败"}
|
|
184
180
|
/>
|
|
185
181
|
);
|
|
186
182
|
}
|
|
@@ -188,29 +184,25 @@ function DefaultErrorState({ error }: { error: PageError }) {
|
|
|
188
184
|
function resolvePageCopy(kind: DefaultPageKind, mode: Mode) {
|
|
189
185
|
if (kind === "process-submit") {
|
|
190
186
|
return {
|
|
191
|
-
description: "
|
|
192
|
-
eyebrow: "Process Submit",
|
|
187
|
+
description: "填写并提交流程申请,提交后可继续查看办理进度。",
|
|
193
188
|
title: "发起流程",
|
|
194
189
|
};
|
|
195
190
|
}
|
|
196
191
|
if (kind === "process-detail" || mode === "process") {
|
|
197
192
|
return {
|
|
198
|
-
description: "
|
|
199
|
-
eyebrow: "Process Detail",
|
|
193
|
+
description: "查看流程内容、办理进度和可执行操作。",
|
|
200
194
|
title: "流程详情",
|
|
201
195
|
};
|
|
202
196
|
}
|
|
203
197
|
if (kind === "form-detail") {
|
|
204
198
|
return {
|
|
205
|
-
description: "
|
|
206
|
-
eyebrow: "Form Detail",
|
|
199
|
+
description: "查看业务记录详情和相关信息。",
|
|
207
200
|
title: "表单详情",
|
|
208
201
|
};
|
|
209
202
|
}
|
|
210
203
|
return {
|
|
211
|
-
description: "
|
|
212
|
-
|
|
213
|
-
title: "发起表单",
|
|
204
|
+
description: "填写并提交业务申请,提交成功后可查看记录详情。",
|
|
205
|
+
title: "发起申请",
|
|
214
206
|
};
|
|
215
207
|
}
|
|
216
208
|
|
|
@@ -1,66 +1,71 @@
|
|
|
1
|
-
import { ArrowRight, FileText, Inbox, Search,
|
|
1
|
+
import { ArrowRight, FileText, Inbox, Search, ShieldCheck } from "lucide-react";
|
|
2
2
|
|
|
3
|
+
import { portalEntries, recentActivities } from "@/app/starter-content";
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "@/shared/
|
|
5
|
+
ListItem,
|
|
6
|
+
MetricCard,
|
|
7
|
+
PageHeader,
|
|
8
|
+
Panel,
|
|
9
|
+
StatusPill,
|
|
10
|
+
} from "@/shared/ui";
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
{ desc: "打开常用表单和流程", icon: FileText, title: "发起申请", tone: "blue" as const },
|
|
13
|
-
{ desc: "处理审批与办理任务", icon: Inbox, title: "我的待办", tone: "amber" as const },
|
|
14
|
-
{ desc: "查看有权限的数据列表", icon: Search, title: "数据查询", tone: "emerald" as const },
|
|
15
|
-
];
|
|
12
|
+
const icons = [FileText, Inbox, Search];
|
|
16
13
|
|
|
17
14
|
export function UserPortalPage() {
|
|
18
15
|
return (
|
|
19
16
|
<div className="min-w-0 space-y-5">
|
|
20
|
-
<
|
|
21
|
-
description="
|
|
22
|
-
eyebrow="User Portal"
|
|
17
|
+
<PageHeader
|
|
18
|
+
description="普通用户可以在这里发起申请、查看事项进度,并查询自己有权限访问的数据。"
|
|
23
19
|
meta={
|
|
24
20
|
<>
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
<
|
|
21
|
+
<StatusPill tone="emerald">已登录</StatusPill>
|
|
22
|
+
<StatusPill tone="blue">服务入口</StatusPill>
|
|
23
|
+
<StatusPill tone="violet">我的事项</StatusPill>
|
|
28
24
|
</>
|
|
29
25
|
}
|
|
30
26
|
title="用户门户"
|
|
31
27
|
/>
|
|
28
|
+
|
|
32
29
|
<section className="grid gap-4 md:grid-cols-3">
|
|
33
|
-
{
|
|
34
|
-
<
|
|
30
|
+
{portalEntries.map((entry, index) => (
|
|
31
|
+
<MetricCard
|
|
35
32
|
caption={entry.desc}
|
|
36
|
-
icon={
|
|
37
|
-
key={entry.
|
|
38
|
-
label={entry.
|
|
33
|
+
icon={icons[index]}
|
|
34
|
+
key={entry.label}
|
|
35
|
+
label={entry.label}
|
|
39
36
|
tone={entry.tone}
|
|
40
37
|
value={<span className="text-base">进入</span>}
|
|
41
38
|
/>
|
|
42
39
|
))}
|
|
43
40
|
</section>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<div className="
|
|
41
|
+
|
|
42
|
+
<section className="grid gap-5 lg:grid-cols-[minmax(0,1fr)_360px]">
|
|
43
|
+
<Panel title="我的事项" description="常用事项会集中展示,便于持续跟进。">
|
|
44
|
+
<div className="grid gap-3 md:grid-cols-2">
|
|
45
|
+
{portalEntries.map(entry => (
|
|
46
|
+
<ListItem key={entry.label} tone={entry.tone}>
|
|
47
|
+
<div className="flex items-center justify-between gap-3">
|
|
48
|
+
<div className="min-w-0">
|
|
49
|
+
<div className="truncate text-sm font-semibold text-slate-950">{entry.label}</div>
|
|
50
|
+
<div className="mt-1 truncate text-xs text-slate-500">{entry.desc}</div>
|
|
51
|
+
</div>
|
|
52
|
+
<ArrowRight className="shrink-0 text-slate-400" size={17} />
|
|
52
53
|
</div>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
</ListItem>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
</Panel>
|
|
58
|
+
|
|
59
|
+
<Panel title="最近动态">
|
|
60
|
+
<div className="space-y-3">
|
|
61
|
+
{recentActivities.slice(0, 3).map(activity => (
|
|
62
|
+
<ListItem icon={<ShieldCheck size={17} />} key={activity} tone="emerald">
|
|
63
|
+
<div className="text-sm leading-6 text-slate-600">{activity}</div>
|
|
64
|
+
</ListItem>
|
|
65
|
+
))}
|
|
66
|
+
</div>
|
|
67
|
+
</Panel>
|
|
68
|
+
</section>
|
|
64
69
|
</div>
|
|
65
70
|
);
|
|
66
71
|
}
|
|
@@ -1,50 +1,49 @@
|
|
|
1
1
|
import { FileCheck2, Globe2, LockKeyhole, MessageSquareText } from "lucide-react";
|
|
2
2
|
|
|
3
|
+
import { publicServices } from "@/app/starter-content";
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@/shared/
|
|
5
|
+
ListItem,
|
|
6
|
+
PageHeader,
|
|
7
|
+
Panel,
|
|
8
|
+
StatusPill,
|
|
9
|
+
} from "@/shared/ui";
|
|
10
|
+
|
|
11
|
+
const icons = [Globe2, FileCheck2, LockKeyhole];
|
|
9
12
|
|
|
10
13
|
export function PublicHomePage() {
|
|
11
14
|
return (
|
|
12
15
|
<div className="min-w-0 space-y-5">
|
|
13
|
-
<
|
|
14
|
-
description="
|
|
15
|
-
eyebrow="Public Runtime"
|
|
16
|
+
<PageHeader
|
|
17
|
+
description="这里用于承载无需登录即可访问的说明、登记、查询或邀请链接。"
|
|
16
18
|
meta={
|
|
17
19
|
<>
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
<
|
|
20
|
+
<StatusPill tone="blue">公开说明</StatusPill>
|
|
21
|
+
<StatusPill tone="emerald">公开登记</StatusPill>
|
|
22
|
+
<StatusPill tone="amber">安全链接</StatusPill>
|
|
21
23
|
</>
|
|
22
24
|
}
|
|
23
|
-
title="
|
|
25
|
+
title="公开服务"
|
|
24
26
|
/>
|
|
25
|
-
<
|
|
27
|
+
<Panel title="可用服务" description="把面向外部用户或访客的入口集中展示,降低访问成本。">
|
|
26
28
|
<div className="grid gap-3 md:grid-cols-3">
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<div className="text-sm font-semibold text-slate-950">Ticket 校验</div>
|
|
37
|
-
<div className="mt-1 text-xs text-slate-500">文件预览、邀请链接等短期凭证入口。</div>
|
|
38
|
-
</MacListItem>
|
|
29
|
+
{publicServices.map((service, index) => {
|
|
30
|
+
const Icon = icons[index];
|
|
31
|
+
return (
|
|
32
|
+
<ListItem icon={<Icon size={17} />} key={service.label} tone={service.tone}>
|
|
33
|
+
<div className="text-sm font-semibold text-slate-950">{service.label}</div>
|
|
34
|
+
<div className="mt-1 text-xs leading-5 text-slate-500">{service.desc}</div>
|
|
35
|
+
</ListItem>
|
|
36
|
+
);
|
|
37
|
+
})}
|
|
39
38
|
</div>
|
|
40
|
-
</
|
|
41
|
-
<
|
|
42
|
-
<
|
|
39
|
+
</Panel>
|
|
40
|
+
<Panel title="访问说明">
|
|
41
|
+
<ListItem icon={<MessageSquareText size={17} />} tone="violet">
|
|
43
42
|
<div className="text-sm leading-6 text-slate-600">
|
|
44
|
-
|
|
43
|
+
公开页面适合发布说明、收集反馈和提供一次性访问入口。涉及敏感数据时,仍应通过后端权限和短期凭证控制访问范围。
|
|
45
44
|
</div>
|
|
46
|
-
</
|
|
47
|
-
</
|
|
45
|
+
</ListItem>
|
|
46
|
+
</Panel>
|
|
48
47
|
</div>
|
|
49
48
|
);
|
|
50
49
|
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Compass, Home } from "lucide-react";
|
|
2
2
|
import { useParams } from "react-router-dom";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { PrimaryButton, SecondaryButton, StatePage } from "@/shared/ui";
|
|
5
5
|
|
|
6
6
|
export function NotFoundPage() {
|
|
7
7
|
const { appType = process.env.OPENXIANGDA_APP_TYPE || "" } = useParams();
|
|
8
8
|
const home = appType ? `/view/${appType}/admin` : "/";
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
|
-
<
|
|
11
|
+
<StatePage
|
|
12
12
|
actions={
|
|
13
13
|
<>
|
|
14
|
-
<
|
|
14
|
+
<SecondaryButton onClick={() => window.history.back()}>
|
|
15
15
|
<Compass size={17} />
|
|
16
16
|
返回上一页
|
|
17
|
-
</
|
|
18
|
-
<
|
|
17
|
+
</SecondaryButton>
|
|
18
|
+
<PrimaryButton onClick={() => window.location.assign(home)}>
|
|
19
19
|
<Home size={17} />
|
|
20
20
|
返回入口
|
|
21
|
-
</
|
|
21
|
+
</PrimaryButton>
|
|
22
22
|
</>
|
|
23
23
|
}
|
|
24
|
-
description="
|
|
24
|
+
description="当前访问的页面不存在,可能是链接已变更或你没有从正确入口进入。"
|
|
25
25
|
fullScreen
|
|
26
26
|
icon={<Compass size={24} />}
|
|
27
27
|
status="404"
|
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"menus": [
|
|
3
3
|
{
|
|
4
|
-
"code": "
|
|
5
|
-
"name": "
|
|
4
|
+
"code": "admin_dashboard",
|
|
5
|
+
"name": "业务工作台",
|
|
6
6
|
"type": "nav",
|
|
7
7
|
"routeCode": "admin.dashboard",
|
|
8
8
|
"path": "/view/:appType/admin",
|
|
9
9
|
"icon": "LayoutDashboard",
|
|
10
10
|
"sortOrder": 10
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"code": "task_center",
|
|
14
|
+
"name": "待办中心",
|
|
15
|
+
"type": "nav",
|
|
16
|
+
"routeCode": "admin.tasks",
|
|
17
|
+
"path": "/view/:appType/admin/tasks",
|
|
18
|
+
"icon": "Inbox",
|
|
19
|
+
"sortOrder": 20
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"code": "service_center",
|
|
23
|
+
"name": "服务入口",
|
|
24
|
+
"type": "nav",
|
|
25
|
+
"routeCode": "admin.services",
|
|
26
|
+
"path": "/view/:appType/admin/services",
|
|
27
|
+
"icon": "ClipboardList",
|
|
28
|
+
"sortOrder": 30
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"code": "data_center",
|
|
32
|
+
"name": "数据中心",
|
|
33
|
+
"type": "nav",
|
|
34
|
+
"routeCode": "admin.data",
|
|
35
|
+
"path": "/view/:appType/admin/data",
|
|
36
|
+
"icon": "Database",
|
|
37
|
+
"sortOrder": 40
|
|
38
|
+
},
|
|
12
39
|
{
|
|
13
40
|
"code": "user_portal",
|
|
14
41
|
"name": "用户门户",
|
|
@@ -16,16 +43,16 @@
|
|
|
16
43
|
"routeCode": "portal.home",
|
|
17
44
|
"path": "/view/:appType/portal",
|
|
18
45
|
"icon": "Home",
|
|
19
|
-
"sortOrder":
|
|
46
|
+
"sortOrder": 50
|
|
20
47
|
},
|
|
21
48
|
{
|
|
22
49
|
"code": "public_home",
|
|
23
|
-
"name": "
|
|
50
|
+
"name": "公开服务",
|
|
24
51
|
"type": "nav",
|
|
25
52
|
"routeCode": "public.home",
|
|
26
53
|
"path": "/view/:appType/public",
|
|
27
54
|
"icon": "Globe",
|
|
28
|
-
"sortOrder":
|
|
55
|
+
"sortOrder": 60
|
|
29
56
|
}
|
|
30
57
|
]
|
|
31
58
|
}
|
package/templates/openxiangda-react-spa/src/resources/permissions/page-groups/app-admin.json
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"code": "app_admin_spa_pages",
|
|
3
|
-
"name": "
|
|
3
|
+
"name": "应用管理员页面权限",
|
|
4
4
|
"roles": ["app_admin"],
|
|
5
|
-
"menuCodes": [
|
|
6
|
-
|
|
5
|
+
"menuCodes": [
|
|
6
|
+
"admin_dashboard",
|
|
7
|
+
"task_center",
|
|
8
|
+
"service_center",
|
|
9
|
+
"data_center",
|
|
10
|
+
"user_portal",
|
|
11
|
+
"public_home"
|
|
12
|
+
],
|
|
13
|
+
"routeCodes": [
|
|
14
|
+
"admin.dashboard",
|
|
15
|
+
"admin.tasks",
|
|
16
|
+
"admin.services",
|
|
17
|
+
"admin.data",
|
|
18
|
+
"portal.home",
|
|
19
|
+
"public.home"
|
|
20
|
+
],
|
|
7
21
|
"pathPatterns": ["/view/:appType/admin/*", "/view/:appType/portal/*", "/view/:appType/public/*"]
|
|
8
22
|
}
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
{
|
|
4
4
|
"code": "app_admin",
|
|
5
5
|
"name": "应用管理员",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "可访问业务工作台、待办中心、服务入口、数据中心和门户页面"
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"code": "app_user",
|
|
10
10
|
"name": "普通用户",
|
|
11
|
-
"description": "
|
|
11
|
+
"description": "可访问用户门户和被授权的业务服务"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -282,7 +282,7 @@ export function MacListItem({
|
|
|
282
282
|
|
|
283
283
|
export function MacDiagnosticPanel({
|
|
284
284
|
data,
|
|
285
|
-
title = "
|
|
285
|
+
title = "详细信息",
|
|
286
286
|
}: {
|
|
287
287
|
data: unknown;
|
|
288
288
|
title?: string;
|
|
@@ -291,7 +291,7 @@ export function MacDiagnosticPanel({
|
|
|
291
291
|
<details className="group rounded-2xl border border-slate-200/80 bg-white/70 p-4">
|
|
292
292
|
<summary className="cursor-pointer select-none text-sm font-semibold text-slate-700">
|
|
293
293
|
{title}
|
|
294
|
-
<span className="ml-2 text-xs font-normal text-slate-400"
|
|
294
|
+
<span className="ml-2 text-xs font-normal text-slate-400">展开查看完整内容</span>
|
|
295
295
|
</summary>
|
|
296
296
|
<pre className="ox-scrollbar mt-4 max-h-96 overflow-auto rounded-2xl bg-slate-950 p-4 text-xs leading-6 text-slate-100">
|
|
297
297
|
{JSON.stringify(data, null, 2)}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export {
|
|
2
|
+
MacListItem as ListItem,
|
|
3
|
+
MacMetricCard as MetricCard,
|
|
4
|
+
MacPageHeader as PageHeader,
|
|
5
|
+
MacPanel as Panel,
|
|
6
|
+
MacPrimaryButton as PrimaryButton,
|
|
7
|
+
MacSecondaryButton as SecondaryButton,
|
|
8
|
+
MacStatePage as StatePage,
|
|
9
|
+
MacStatusPill as StatusPill,
|
|
10
|
+
MacTrendBars as TrendBars,
|
|
11
|
+
cn,
|
|
12
|
+
type MacTone as AppTone,
|
|
13
|
+
} from "./mac-admin";
|