ow
This commit is contained in:
1 parent
9344b56334
commit
441d1e821e
37 files changed
+3706
-23
No files matched your search
@@ -8,11 +8,16 @@
|
||||
<div class="page-main ft-page">
|
||||
<DashboardGroupCard v-for="grp in groups" :id="'grp-' + grp.key" :key="grp.key" :name="grp.name"
|
||||
:color="grp.color" :soft="grp.soft" :icon="grp.icon" :layout="grp.layout" :cover="grp.cover"
|
||||
:badge="grp.badge" :items="grp.items" @navigate="onpush" />
|
||||
:badge="grp.badge" :items="grp.items" @navigate="onpush" @help="onHelp" />
|
||||
|
||||
<a-empty v-if="!groups.length && !loading" description="没有匹配的功能" />
|
||||
</div>
|
||||
|
||||
<!-- 新手帮助:统一挂在页面上,由行尾图标触发,按 FunctionName 分发不同文档 -->
|
||||
<HelpTimelineModal v-model:open="helpOpen" :function-name="helpTarget?.FunctionName"
|
||||
:title="helpTarget?.FunctionLocalName || helpTarget?.FunctionName" :color="helpColor" :soft="helpSoft"
|
||||
:icon="helpIcon" />
|
||||
|
||||
<!-- 底部快捷栏:与其它页面一致,固定在底部 -->
|
||||
<div class="page-footer dash-footer">
|
||||
<DashboardBottomNav :items="navItems" @jump="onNavClick" />
|
||||
@@ -29,6 +34,7 @@ import type { SecurityFunctionDisplayData } from "@/data/auto/securityFunctionDi
|
||||
import DashboardHero from "@/components/dashboard/DashboardHero.vue";
|
||||
import DashboardGroupCard, { type GroupCardItem } from "@/components/dashboard/DashboardGroupCard.vue";
|
||||
import DashboardBottomNav from "@/components/dashboard/DashboardBottomNav.vue";
|
||||
import HelpTimelineModal from "@/components/basic/HelpTimelineModal.vue";
|
||||
|
||||
interface NavItem {
|
||||
key: string;
|
||||
@@ -94,7 +100,7 @@ const resolveGroup = (it: SecurityFunctionDisplayData): GroupKey =>
|
||||
/* ==================== 自定义副标题 ==================== */
|
||||
/** 留空时卡片会自动回退到 FunctionEngName */
|
||||
const SUBTITLE_OF: Record<string, string> = {
|
||||
DmsFileEnquiry: "上传、下载",
|
||||
DmsFileEnquiry: "",
|
||||
DmsFileDeleteEnquiry: "",
|
||||
FamilyGroupShare: "",
|
||||
FamilyShareOperation: "",
|
||||
@@ -103,7 +109,7 @@ const SUBTITLE_OF: Record<string, string> = {
|
||||
Preview: "",
|
||||
PublishPhotoOperation: "",
|
||||
PublishPhotoEnquiry: "",
|
||||
PreviewAudio: "播放从默认专辑",
|
||||
PreviewAudio: "",
|
||||
PublishAudioOperation: "",
|
||||
PublishAudioEnquiry: "",
|
||||
PreviewVideo: "",
|
||||
@@ -127,7 +133,7 @@ const groups = computed(() => {
|
||||
const items: GroupCardItem[] = [];
|
||||
for (const it of allItems.value) {
|
||||
if (resolveGroup(it) !== g.key) continue;
|
||||
const label = it.FunctionLocalName || it.FunctionName;
|
||||
const label = it.FunctionLocalName || it.FunctionEngName;
|
||||
if (taken.has(label)) continue;
|
||||
taken.add(label);
|
||||
items.push({ ...it, subtitle: resolveSubtitle(it) });
|
||||
@@ -149,6 +155,36 @@ const navItems = computed<NavItem[]>(() =>
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* 按左侧菜单的顺序排列。
|
||||
*
|
||||
* Orderby 只在「同一个父节点下」才是连续有意义的序号,跨父组直接比大小会错:
|
||||
* 某个父组(比如从「有家网盘」拆出来的组)内部可能从 0 重新计数,
|
||||
* 它的子项就会被平铺排序甩到全局最前面。
|
||||
*
|
||||
* 所以这里先按父节点自身的序号把「组」排好,再在组内按 Orderby 排,
|
||||
* 平铺出来的先后就和菜单的树形展开顺序一致。
|
||||
*/
|
||||
const sortByMenuOrder = (list: SecurityFunctionDisplayData[]): SecurityFunctionDisplayData[] => {
|
||||
// 每个节点自己的序号,用作它作为「父」时的排序依据
|
||||
const parentOrder = new Map<string, number>();
|
||||
list.forEach((it) => {
|
||||
if (it.FunctionName) parentOrder.set(it.FunctionName, it.Orderby ?? 0);
|
||||
});
|
||||
|
||||
/** 有父节点就跟着父走,没有(顶层)就用自己的序号 */
|
||||
const groupOrder = (it: SecurityFunctionDisplayData): number => {
|
||||
if (it.FunctionNameParent && parentOrder.has(it.FunctionNameParent)) {
|
||||
return parentOrder.get(it.FunctionNameParent)!;
|
||||
}
|
||||
return it.Orderby ?? 0;
|
||||
};
|
||||
|
||||
return [...list].sort(
|
||||
(a, b) => groupOrder(a) - groupOrder(b) || (a.Orderby ?? 0) - (b.Orderby ?? 0)
|
||||
);
|
||||
};
|
||||
|
||||
/* ==================== 交互 ==================== */
|
||||
const onpush = (apiRoute: string) => {
|
||||
if (apiRoute) router.push(apiRoute);
|
||||
@@ -157,13 +193,43 @@ const onNavClick = (key: string) => {
|
||||
document.getElementById("grp-" + key)?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
};
|
||||
|
||||
/* ==================== 新手帮助弹窗 ==================== */
|
||||
const helpOpen = ref(false);
|
||||
/** 当前请求帮助的功能项,决定 HelpTimelineModal 加载哪份文档 */
|
||||
const helpTarget = ref<GroupCardItem | null>(null);
|
||||
|
||||
/** 帮助弹窗沿用所属分组的主题色,与卡片保持视觉一致 */
|
||||
const helpTheme = computed(() => {
|
||||
const key = helpTarget.value ? resolveGroup(helpTarget.value) : undefined;
|
||||
return groupDefs.find(g => g.key === key) ?? groupDefs[groupDefs.length - 1];
|
||||
});
|
||||
const helpColor = computed(() => helpTheme.value.color);
|
||||
const helpSoft = computed(() => helpTheme.value.soft);
|
||||
const helpIcon = computed(() => helpTheme.value.icon);
|
||||
|
||||
const onHelp = (it: GroupCardItem) => {
|
||||
helpTarget.value = it;
|
||||
helpOpen.value = true;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const fd = await securityUserService.FindMenuByUsername();
|
||||
const raw = fd?.SecurityFunctionDisplayDatas ?? [];
|
||||
allItems.value = raw.filter(
|
||||
it => it.FunctionIndc !== "N" && (it.PageUrl?.indexOf("master") ?? -1) > 0
|
||||
|
||||
// 有些功能会挂在「不存在的父节点」下(例如测试残留的 abc),
|
||||
// 它和正式记录同名却属于另一条,按 Orderby 排序时会窜到最前面,
|
||||
// 表现为首页位置与左侧菜单对不上、改了后台顺序也不生效。
|
||||
// 这里剔掉这类孤立记录,只保留父节点真实存在的。
|
||||
const knownFunctions = new Set(raw.map(it => it.FunctionName));
|
||||
allItems.value = sortByMenuOrder(
|
||||
raw.filter(
|
||||
it =>
|
||||
it.FunctionIndc !== "N" &&
|
||||
(it.PageUrl?.indexOf("master") ?? -1) > 0 &&
|
||||
(!it.FunctionNameParent || knownFunctions.has(it.FunctionNameParent))
|
||||
)
|
||||
);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
@@ -99,6 +99,13 @@
|
||||
<a-input size="large" placeholder="请输入页面名称" :readonly="!isEdit"
|
||||
v-model:value="data.SecurityFunction.PageName" />
|
||||
</div>
|
||||
<!-- 备注:内容可能较长,占满整行显示 -->
|
||||
<div class="ft-field ft-field-full">
|
||||
<div class="ft-label">备注</div>
|
||||
<a-textarea :auto-size="{ minRows: 3, maxRows: 10 }" :maxlength="1000"
|
||||
placeholder="请输入备注" :readonly="!isEdit"
|
||||
v-model:value="data.SecurityFunction.Remark" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in new issue
Block a user