diff --git a/client/src/features/mobile/navigation.ts b/client/src/features/mobile/navigation.ts
index 94508e86..432d209a 100644
--- a/client/src/features/mobile/navigation.ts
+++ b/client/src/features/mobile/navigation.ts
@@ -30,6 +30,6 @@ export type MobileNavItem = {
export const MOBILE_NAV_ITEMS: MobileNavItem[] = [
{ key: "home", to: "/mobile", label: "首页", icon: "home" },
{ key: "approvals", to: "/mobile/approvals", label: "审批", icon: "fact_check", anyOf: MOBILE_APPROVAL_PERMISSIONS },
- { key: "capture", to: "/mobile/capture", label: "拍照", icon: "photo_camera", anyOf: MOBILE_CAPTURE_PERMISSIONS },
+ { key: "capture", to: "/mobile/capture", label: "票据", icon: "receipt_long", anyOf: MOBILE_CAPTURE_PERMISSIONS },
{ key: "me", to: "/mobile/me", label: "我的", icon: "person" },
];
diff --git a/client/src/layouts/AppShellLayout.tsx b/client/src/layouts/AppShellLayout.tsx
index 6282f364..87ca44e2 100644
--- a/client/src/layouts/AppShellLayout.tsx
+++ b/client/src/layouts/AppShellLayout.tsx
@@ -30,9 +30,11 @@ export function AppShellLayout() {
-
+
+
+
-
+
diff --git a/client/src/pages/MobileMePage.tsx b/client/src/pages/MobileMePage.tsx
index 7ea2b4ef..608ad10b 100644
--- a/client/src/pages/MobileMePage.tsx
+++ b/client/src/pages/MobileMePage.tsx
@@ -6,6 +6,7 @@ import { fetchEmployeeProfile } from "../api/employees";
import { mapApiErrorMessage } from "../api/errorMessages";
import { isApiError } from "../api/types";
import { useAuth } from "../auth/AuthContext";
+import { hasAnyPermission } from "../auth/permissions";
import { EmployeeAvatar } from "../components/common/EmployeeAvatar";
import { PageHeader } from "../components/common/PageHeader";
import { PageScaffold } from "../components/patterns/PageScaffold";
@@ -22,8 +23,39 @@ function resolveErrorMessage(error: unknown) {
return "请求失败,请稍后重试。";
}
+function MobileActionLink({
+ to,
+ label,
+ description,
+ icon,
+}: {
+ to: string;
+ label: string;
+ description: string;
+ icon: string;
+}) {
+ return (
+
+
+ {icon}
+
+
+ {label}
+ {description}
+
+
+ );
+}
+
export function MobileMePage() {
- const { me, refreshMe } = useAuth();
+ const { me, permissions, refreshMe, logout } = useAuth();
+ const canAccessApprovals = hasAnyPermission(permissions, ["expense.approve", "leave.approve", "procurement.approve", "travel.approve"]);
+ const canAccessAdmin = hasAnyPermission(permissions, ["*", "system.settings", "system.users", "report.dashboard.view"]);
+ const canAccessAssets = hasAnyPermission(permissions, ["asset.view_own", "asset.view_all", "asset.manage", "asset.transfer", "asset.inventory"]);
+ const canAccessProjects = hasAnyPermission(permissions, ["project.view_own", "project.view_all", "project.manage"]);
const profileQuery = useQuery({
enabled: Boolean(me?.id),
@@ -49,7 +81,7 @@ export function MobileMePage() {
@@ -70,14 +102,36 @@ export function MobileMePage() {
) : null}
-
- {me?.id ? (
-
- ) : null}
+
+
+
+ {me?.id ? (
+
+ ) : null}
+
+
+
+
+
+
+ {canAccessApprovals ? : null}
+ {canAccessAssets ? : null}
+ {canAccessProjects ? : null}
+
+
+
+ {canAccessAdmin ? (
+
+
+
+
+
+
+
+ ) : null}
+
+
+
);
}
diff --git a/client/src/pages/MobilePortalPage.tsx b/client/src/pages/MobilePortalPage.tsx
index 52941e6e..75d2d354 100644
--- a/client/src/pages/MobilePortalPage.tsx
+++ b/client/src/pages/MobilePortalPage.tsx
@@ -315,14 +315,45 @@ export function MobilePortalPage() {
const teamStatusItems = teamStatusQuery.data ?? [];
const pendingTasks = pendingCountQuery.data?.items ?? [];
const notifications = notificationsQuery.data?.items ?? [];
+ const pendingApprovalCount = canAccessApprovals ? pendingCountQuery.data?.total ?? 0 : 0;
+ const unreadNotificationCount = notifications.filter((item) => !item.readAt).length;
return (
+
+
+
+
今日重点
+
移动端只保留高频动作,低频模块放到“我的”。
+
+
0 ? "badge-warning" : "badge-success"}>
+ {pendingApprovalCount > 0 ? `${pendingApprovalCount} 条待审批` : "暂无审批待办"}
+
+
+
+
+
+
{pendingApprovalCount}
+
审批待办
+
+
+
{unreadNotificationCount}
+
未读通知
+
+
+
+
+
+
+
+
+
+
{!attendanceFeatureDisabled ? (
@@ -524,15 +555,15 @@ export function MobilePortalPage() {
)}
-
+ {(canAccessLeave || canAccessAssetScan) ? (
+
+ ) : null}