From 8151c3253dc287a79914bc08414af17dfb380c96 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期三, 14 十月 2026 14:34:33 +0800
Subject: [PATCH] refactor(首页): 展示模块改为跟随菜单权限自动隐藏
---
src/views/mes/home/modules/work-order-chart.vue | 13
src/views/dashboard/analytics/modules/quick-actions.vue | 17
src/utils/use-home-access.ts | 56 +++++
src/views/mes/home/index.vue | 67 +++++
src/views/dashboard/analytics/modules/biz-cards.vue | 14
src/views/mes/home/modules/kpi-cards.vue | 55 ++++
/dev/null | 30 --
src/views/mes/home/modules/production-trend.vue | 12
src/views/dashboard/analytics/modules/alert-panel.vue | 13
src/views/dashboard/analytics/modules/kpi-cards.vue | 28 +-
src/views/dashboard/analytics/modules/production-trend.vue | 7
src/views/dashboard/analytics/index.vue | 53 ++++
src/views/mes/home/modules/shortcuts.vue | 73 +-----
src/views/mes/home/data.ts | 101 +++++++++
src/views/mes/home/modules/alert-panel.vue | 64 +++--
15 files changed, 420 insertions(+), 183 deletions(-)
diff --git a/src/utils/use-home-access.ts b/src/utils/use-home-access.ts
new file mode 100644
index 0000000..0fe0ba0
--- /dev/null
+++ b/src/utils/use-home-access.ts
@@ -0,0 +1,56 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { computed } from 'vue';
+
+import { useAccess } from '@vben/access';
+import { useAccessStore } from '@vben/stores';
+
+/** 棣栭〉甯搁┗锛屼笟鍔℃暟鎹拰鍏ュ彛浠嶉渶閬靛惊褰撳墠鐢ㄦ埛鐨勮彍鍗曟潈闄愩�� */
+export function useHomeAccess() {
+ const accessStore = useAccessStore();
+ const { hasAccessByCodes } = useAccess();
+
+ function canQuery(permission: string) {
+ return hasAccessByCodes([permission, '*:*:*']);
+ }
+
+ function canNavigate(name: string) {
+ function contains(routes: RouteRecordRaw[]): boolean {
+ return routes.some((route) => {
+ if (route.meta?.menuVisibleWithForbidden) return false;
+ return route.name === name || contains(route.children ?? []);
+ });
+ }
+ return contains(accessStore.accessRoutes);
+ }
+
+ /**
+ * 璇ヨ彍鍗曞褰撳墠鐢ㄦ埛鏄惁銆屽紑鐫�銆嶁�斺�� 鐢ㄤ簬棣栭〉妯″潡寮�鍏炽��
+ *
+ * 鍚庣鑿滃崟 `visible = 0` 浼氳鍓嶇杞垚璺敱鐨� `meta.hideInMenu`锛岃繖绫昏矾鐢变粛鐒舵敞鍐屽湪
+ * router 閲岋紙`canNavigate` 涓� true锛岄〉闈㈠彲浠ョ洿鎺ヨ闂級锛屽彧鏄暣妫靛瓙鏍戜笉浼氬嚭鐜板湪渚ц竟鏍忋��
+ * 鎵�浠ュ垽鏂�岃繖涓ā鍧楁湁娌℃湁寮�銆嶄笉鑳藉彧鐪嬭矾鐢辨槸鍚﹀瓨鍦紝杩樿鐪嬪畠鍜屽畠鐨勬瘡涓�绾х鍏堟槸鍚﹀彲瑙併��
+ */
+ function canSeeMenu(name: string) {
+ function find(
+ routes: RouteRecordRaw[],
+ ancestorHidden: boolean,
+ ): boolean | undefined {
+ for (const route of routes) {
+ const hidden =
+ ancestorHidden ||
+ route.meta?.hideInMenu === true ||
+ route.meta?.menuVisibleWithForbidden === true;
+ if (route.name === name) return !hidden;
+ const found = find(route.children ?? [], hidden);
+ if (found !== undefined) return found;
+ }
+ return undefined;
+ }
+ return find(accessStore.accessRoutes, false) === true;
+ }
+
+ const canViewHome = computed(() => canQuery('mes:home:query'));
+
+ return { canNavigate, canQuery, canSeeMenu, canViewHome };
+}
diff --git a/src/views/dashboard/analytics/index.vue b/src/views/dashboard/analytics/index.vue
index 907fac8..cdf7447 100644
--- a/src/views/dashboard/analytics/index.vue
+++ b/src/views/dashboard/analytics/index.vue
@@ -8,6 +8,8 @@
import { getHomeSummary } from '#/api/mes/home';
+import { useHomeAccess } from '#/utils/use-home-access';
+
import { defaultSummary } from './data';
import AiInsights from './modules/ai-insights.vue';
import AlertPanel from './modules/alert-panel.vue';
@@ -15,13 +17,34 @@
import KpiCards from './modules/kpi-cards.vue';
import ProductionTrend from './modules/production-trend.vue';
import QuickActions from './modules/quick-actions.vue';
-import { useHomeAccess } from './use-home-access';
defineOptions({ name: 'DashboardAnalytics' });
const router = useRouter();
const summary = ref(defaultSummary);
-const { canNavigate, canViewHome } = useHomeAccess();
+const { canNavigate, canSeeMenu, canViewHome } = useHomeAccess();
+
+// 棣栭〉妯″潡璺熼殢渚ц竟鏍忚彍鍗曪細鑿滃崟娌″紑鐨勬ā鍧楁暣鍧椾笉灞曠ず
+/** MES 鐢熶骇 KPI锛氫换鎰忎竴寮犲崱鐨勮彍鍗曞紑鐫�灏辨覆鏌撴暣琛� */
+const showKpi = computed(
+ () =>
+ canViewHome.value &&
+ ['MesProWorkOrder', 'MesProFeedback', 'MesQcIqc', 'MesDvMachinery'].some(
+ (name) => canSeeMenu(name),
+ ),
+);
+/** AI 鏅鸿兘鍒嗘瀽锛欰I 妯″潡鐨勮彍鍗曞紑鐫�鎵嶆覆鏌� */
+const showAiInsights = computed(
+ () => canViewHome.value && canSeeMenu('AiChat'),
+);
+/** 鐢熶骇瓒嬪娍锛氭暟鎹潵鑷敓浜ф姤宸� */
+const showTrend = computed(
+ () => canViewHome.value && canSeeMenu('MesProFeedback'),
+);
+/** 宸ュ崟鐘舵�佸垎甯冿細鏁版嵁鏉ヨ嚜鐢熶骇璁㈠崟 */
+const showWorkOrderStatus = computed(
+ () => canViewHome.value && canSeeMenu('MesProWorkOrder'),
+);
const greeting = computed(() => {
const hour = new Date().getHours();
@@ -76,21 +99,29 @@
</div>
<!-- MES 鐢熶骇 KPI -->
- <KpiCards v-if="canViewHome" :summary="summary" @navigate="handleNavigate" />
+ <KpiCards v-if="showKpi" :summary="summary" @navigate="handleNavigate" />
<!-- ERP/WMS/BPM 缁忚惀 KPI -->
<BizCards @navigate="handleNavigate" />
<!-- AI 鏅鸿兘鍒嗘瀽 -->
<AiInsights
- v-if="canViewHome && canNavigate('MesProWorkOrder')"
+ v-if="showAiInsights"
:active-order-count="summary.workOrderActiveCount"
@navigate="handleNavigate"
/>
<!-- 鐢熶骇瓒嬪娍 + 棰勮闈㈡澘 -->
- <Row v-if="canViewHome" :gutter="16" class="mb-4">
- <Col :lg="14" :md="24" :sm="24" :xl="14" :xs="24" class="mb-4">
+ <Row v-if="showTrend || showWorkOrderStatus" :gutter="16" class="mb-4">
+ <Col
+ v-if="showTrend"
+ :lg="showWorkOrderStatus ? 14 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showWorkOrderStatus ? 14 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<div class="glass-card rounded-2xl p-5">
<h3 class="mb-4 text-base font-semibold text-gray-800 dark:text-gray-100">
鐢熶骇瓒嬪娍锛堣繎7澶╋級
@@ -98,7 +129,15 @@
<ProductionTrend />
</div>
</Col>
- <Col :lg="10" :md="24" :sm="24" :xl="10" :xs="24" class="mb-4">
+ <Col
+ v-if="showWorkOrderStatus"
+ :lg="showTrend ? 10 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showTrend ? 10 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<AlertPanel
:repair-active-count="summary.repairActiveCount"
@navigate="handleNavigate"
diff --git a/src/views/dashboard/analytics/modules/alert-panel.vue b/src/views/dashboard/analytics/modules/alert-panel.vue
index 4911ffa..59d562c 100644
--- a/src/views/dashboard/analytics/modules/alert-panel.vue
+++ b/src/views/dashboard/analytics/modules/alert-panel.vue
@@ -12,7 +12,7 @@
import { getWorkOrderStatusDistribution } from '#/api/mes/home';
-import { useHomeAccess } from '../use-home-access';
+import { useHomeAccess } from '#/utils/use-home-access';
defineOptions({ name: 'DashboardAlertPanel' });
@@ -27,10 +27,11 @@
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
const loading = ref(false);
-const { canNavigate, canViewHome } = useHomeAccess();
+const { canSeeMenu } = useHomeAccess();
async function loadStatus() {
- if (!canViewHome.value) return;
+ // 宸ュ崟鐘舵�佸垎甯冨彇鑷敓浜ц鍗曪紝璁㈠崟鑿滃崟娌″紑灏变笉璇锋眰
+ if (!canSeeMenu('MesProWorkOrder')) return;
loading.value = true;
try {
const data = await getWorkOrderStatusDistribution();
@@ -72,9 +73,9 @@
<!-- 棰勮鍗$墖琛� -->
<div class="grid grid-cols-1 gap-3">
<div
- v-if="canNavigate('MesProRepair')"
+ v-if="canSeeMenu('MesDvRepair')"
class="glass-tilt group cursor-pointer overflow-hidden rounded-2xl border-0 p-4"
- @click="emit('navigate', 'MesProRepair')"
+ @click="emit('navigate', 'MesDvRepair')"
>
<div class="relative z-10 flex items-center gap-3">
<div class="flex size-10 items-center justify-center rounded-lg bg-amber-50 text-amber-600 shadow-sm dark:bg-amber-500/15 dark:text-amber-400">
@@ -92,7 +93,7 @@
</div>
<!-- 宸ュ崟鐘舵�佸浘 -->
- <div class="glass-tilt rounded-2xl p-5">
+ <div v-if="canSeeMenu('MesProWorkOrder')" class="glass-tilt rounded-2xl p-5">
<h4 class="mb-3 text-sm font-semibold text-gray-800 dark:text-gray-100">
宸ュ崟鐘舵�佸垎甯�
</h4>
diff --git a/src/views/dashboard/analytics/modules/biz-cards.vue b/src/views/dashboard/analytics/modules/biz-cards.vue
index 5fc8ff1..4efb8d5 100644
--- a/src/views/dashboard/analytics/modules/biz-cards.vue
+++ b/src/views/dashboard/analytics/modules/biz-cards.vue
@@ -11,7 +11,7 @@
import { getMaterialStockPage } from '#/api/mes/wm/materialstock';
import { getTaskTodoPage } from '#/api/bpm/task';
-import { useHomeAccess } from '../use-home-access';
+import { useHomeAccess } from '#/utils/use-home-access';
defineOptions({ name: 'DashboardBizCards' });
@@ -23,11 +23,11 @@
const saleCount = ref(0);
const stockCount = ref(0);
const bpmTodoCount = ref(0);
-const { canNavigate, canQuery } = useHomeAccess();
-const canViewPurchase = computed(() => canQuery('erp:purchase-order:query') && canNavigate('ErpPurchaseOrder'));
-const canViewSale = computed(() => canQuery('erp:sale-order:query') && canNavigate('ErpSaleOrder'));
-const canViewStock = computed(() => canQuery('mes:wm-material-stock:query') && canNavigate('MesWmMaterialStock'));
-const canViewBpmTodo = computed(() => canQuery('bpm:task:query') && canNavigate('BpmTaskTodo'));
+const { canSeeMenu, canQuery } = useHomeAccess();
+const canViewPurchase = computed(() => canQuery('erp:purchase-order:query') && canSeeMenu('ErpPurchaseOrder'));
+const canViewSale = computed(() => canQuery('erp:sale-order:query') && canSeeMenu('ErpSaleOrder'));
+const canViewStock = computed(() => canQuery('mes:wm-material-stock:query') && canSeeMenu('MesWmMaterialStock'));
+const canViewBpmTodo = computed(() => canQuery('bpm:task:query') && canSeeMenu('BpmTodoTask'));
async function loadPurchase() {
if (!canViewPurchase.value) return;
@@ -183,7 +183,7 @@
:style="tiltStyle('bpm')"
@mousemove="(e: MouseEvent) => onMouseMove(e, 'bpm')"
@mouseleave="onMouseLeave('bpm')"
- @click="emit('navigate', 'BpmTaskTodo')"
+ @click="emit('navigate', 'BpmTodoTask')"
>
<div class="relative z-10 flex items-center gap-4 p-5">
<div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-red-500 to-rose-400 shadow-lg shadow-red-500/25 transition-transform duration-300 group-hover:scale-110">
diff --git a/src/views/dashboard/analytics/modules/kpi-cards.vue b/src/views/dashboard/analytics/modules/kpi-cards.vue
index 88853ef..733d378 100644
--- a/src/views/dashboard/analytics/modules/kpi-cards.vue
+++ b/src/views/dashboard/analytics/modules/kpi-cards.vue
@@ -8,11 +8,11 @@
import { Col, Row } from 'ant-design-vue';
-import { useHomeAccess } from '../use-home-access';
+import { useHomeAccess } from '#/utils/use-home-access';
defineOptions({ name: 'DashboardKpiCards' });
-const { canNavigate } = useHomeAccess();
+const { canSeeMenu } = useHomeAccess();
const props = defineProps<{
summary: MesHomeApi.Summary;
@@ -63,14 +63,14 @@
<template>
<Row :gutter="16">
<!-- 鐢熶骇璁㈠崟 -->
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col v-if="canSeeMenu('MesProWorkOrder')" :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
<div
class="glass-tilt group overflow-hidden rounded-2xl border-0"
- :class="{ 'cursor-pointer': canNavigate('MesProWorkOrder') }"
+ :class="{ 'cursor-pointer': canSeeMenu('MesProWorkOrder') }"
:style="tiltStyle('order')"
@mousemove="(e: MouseEvent) => onMouseMove(e, 'order')"
@mouseleave="onMouseLeave('order')"
- @click="canNavigate('MesProWorkOrder') && emit('navigate', 'MesProWorkOrder')"
+ @click="canSeeMenu('MesProWorkOrder') && emit('navigate', 'MesProWorkOrder')"
>
<div class="relative z-10 flex items-center gap-4 p-5">
<div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-cyan-400 shadow-lg shadow-blue-500/25 transition-transform duration-300 group-hover:scale-110">
@@ -95,14 +95,14 @@
</Col>
<!-- 浠婃棩浜ч噺 -->
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col v-if="canSeeMenu('MesProFeedback')" :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
<div
class="glass-tilt group overflow-hidden rounded-2xl border-0"
- :class="{ 'cursor-pointer': canNavigate('MesProFeedback') }"
+ :class="{ 'cursor-pointer': canSeeMenu('MesProFeedback') }"
:style="tiltStyle('output')"
@mousemove="(e: MouseEvent) => onMouseMove(e, 'output')"
@mouseleave="onMouseLeave('output')"
- @click="canNavigate('MesProFeedback') && emit('navigate', 'MesProFeedback')"
+ @click="canSeeMenu('MesProFeedback') && emit('navigate', 'MesProFeedback')"
>
<div class="relative z-10 flex items-center gap-4 p-5">
<div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-emerald-500 to-green-400 shadow-lg shadow-emerald-500/25 transition-transform duration-300 group-hover:scale-110">
@@ -127,14 +127,14 @@
</Col>
<!-- 璐ㄩ噺鍚堟牸鐜� -->
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col v-if="canSeeMenu('MesProFeedback')" :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
<div
class="glass-tilt group overflow-hidden rounded-2xl border-0"
- :class="{ 'cursor-pointer': canNavigate('MesQcRecord') }"
+ :class="{ 'cursor-pointer': canSeeMenu('MesProFeedback') }"
:style="tiltStyle('quality')"
@mousemove="(e: MouseEvent) => onMouseMove(e, 'quality')"
@mouseleave="onMouseLeave('quality')"
- @click="canNavigate('MesQcRecord') && emit('navigate', 'MesQcRecord')"
+ @click="canSeeMenu('MesProFeedback') && emit('navigate', 'MesProFeedback')"
>
<div class="relative z-10 flex items-center gap-4 p-5">
<div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-orange-500 to-amber-400 shadow-lg shadow-orange-500/25 transition-transform duration-300 group-hover:scale-110">
@@ -161,14 +161,14 @@
</Col>
<!-- 璁惧杩愯鐜� -->
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col v-if="canSeeMenu('MesDvMachinery')" :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
<div
class="glass-tilt group overflow-hidden rounded-2xl border-0"
- :class="{ 'cursor-pointer': canNavigate('MesDvMachinery') }"
+ :class="{ 'cursor-pointer': canSeeMenu('MesDvMachinery') }"
:style="tiltStyle('equip')"
@mousemove="(e: MouseEvent) => onMouseMove(e, 'equip')"
@mouseleave="onMouseLeave('equip')"
- @click="canNavigate('MesDvMachinery') && emit('navigate', 'MesDvMachinery')"
+ @click="canSeeMenu('MesDvMachinery') && emit('navigate', 'MesDvMachinery')"
>
<div class="relative z-10 flex items-center gap-4 p-5">
<div class="flex size-12 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-violet-500 to-purple-400 shadow-lg shadow-violet-500/25 transition-transform duration-300 group-hover:scale-110">
diff --git a/src/views/dashboard/analytics/modules/production-trend.vue b/src/views/dashboard/analytics/modules/production-trend.vue
index 45bc2bb..cff6e5c 100644
--- a/src/views/dashboard/analytics/modules/production-trend.vue
+++ b/src/views/dashboard/analytics/modules/production-trend.vue
@@ -8,16 +8,17 @@
import { getProductionTrend } from '#/api/mes/home';
-import { useHomeAccess } from '../use-home-access';
+import { useHomeAccess } from '#/utils/use-home-access';
defineOptions({ name: 'DashboardProductionTrend' });
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
-const { canViewHome } = useHomeAccess();
+const { canSeeMenu } = useHomeAccess();
async function loadTrend() {
- if (!canViewHome.value) return;
+ // 鐢熶骇瓒嬪娍鍙栬嚜鐢熶骇鎶ュ伐锛屾姤宸ヨ彍鍗曟病寮�灏变笉璇锋眰
+ if (!canSeeMenu('MesProFeedback')) return;
const data = await getProductionTrend(7);
const dates = data.map((d: MesHomeApi.ProductionTrend) => d.date.slice(5));
const quantities = data.map((d: MesHomeApi.ProductionTrend) => d.quantity);
diff --git a/src/views/dashboard/analytics/modules/quick-actions.vue b/src/views/dashboard/analytics/modules/quick-actions.vue
index d7cc976..58115d0 100644
--- a/src/views/dashboard/analytics/modules/quick-actions.vue
+++ b/src/views/dashboard/analytics/modules/quick-actions.vue
@@ -3,7 +3,7 @@
import { IconifyIcon } from '@vben/icons';
-import { useHomeAccess } from '../use-home-access';
+import { useHomeAccess } from '#/utils/use-home-access';
defineOptions({ name: 'DashboardQuickActions' });
@@ -22,16 +22,17 @@
const actions: QuickAction[] = [
{ title: '鐢熶骇宸ュ崟', icon: 'lucide:file-text', route: 'MesProWorkOrder', gradient: 'from-blue-500 to-cyan-500', shadow: 'shadow-blue-500/15' },
{ title: '鐢熶骇鎶ュ伐', icon: 'lucide:check-square', route: 'MesProFeedback', gradient: 'from-emerald-500 to-green-500', shadow: 'shadow-emerald-500/15' },
- { title: '璐ㄦ绠$悊', icon: 'lucide:clipboard-check', route: 'MesQcRecord', gradient: 'from-orange-500 to-amber-500', shadow: 'shadow-orange-500/15' },
+ { title: '璐ㄦ绠$悊', icon: 'lucide:clipboard-check', route: 'MesQcIqc', gradient: 'from-orange-500 to-amber-500', shadow: 'shadow-orange-500/15' },
{ title: '璁惧鐐规', icon: 'lucide:settings', route: 'MesDvMachinery', gradient: 'from-violet-500 to-purple-500', shadow: 'shadow-violet-500/15' },
- { title: '鐢熶骇鎺掔▼', icon: 'lucide:calendar-range', route: 'MesProScheduling', gradient: 'from-cyan-500 to-teal-500', shadow: 'shadow-cyan-500/15' },
- { title: '鐗╂枡搴撳瓨', icon: 'lucide:package-search', route: 'WlsMaterialStock', gradient: 'from-indigo-500 to-blue-500', shadow: 'shadow-indigo-500/15' },
- { title: '宸ヨ壓璺嚎', icon: 'lucide:route', route: 'MesPdRouting', gradient: 'from-teal-500 to-emerald-500', shadow: 'shadow-teal-500/15' },
- { title: '鏁版嵁鎶ヨ〃', icon: 'lucide:bar-chart-big', route: 'MesHomeIndex', gradient: 'from-pink-500 to-rose-500', shadow: 'shadow-pink-500/15' },
+ { title: '鐢熶骇鎺掔▼', icon: 'lucide:calendar-range', route: 'MesProTask', gradient: 'from-cyan-500 to-teal-500', shadow: 'shadow-cyan-500/15' },
+ { title: '鐗╂枡搴撳瓨', icon: 'lucide:package-search', route: 'MesWmMaterialStock', gradient: 'from-indigo-500 to-blue-500', shadow: 'shadow-indigo-500/15' },
+ { title: '宸ヨ壓璺嚎', icon: 'lucide:route', route: 'MesProcessDesignRoute', gradient: 'from-teal-500 to-emerald-500', shadow: 'shadow-teal-500/15' },
];
-const { canNavigate } = useHomeAccess();
-const accessibleActions = computed(() => actions.filter((action) => canNavigate(action.route)));
+const { canSeeMenu } = useHomeAccess();
+const accessibleActions = computed(() =>
+ actions.filter((action) => canSeeMenu(action.route)),
+);
</script>
<template>
diff --git a/src/views/dashboard/analytics/use-home-access.ts b/src/views/dashboard/analytics/use-home-access.ts
deleted file mode 100644
index 65df114..0000000
--- a/src/views/dashboard/analytics/use-home-access.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router';
-
-import { computed } from 'vue';
-
-import { useAccess } from '@vben/access';
-import { useAccessStore } from '@vben/stores';
-
-/** 棣栭〉甯搁┗锛屼笟鍔℃暟鎹拰鍏ュ彛浠嶉渶閬靛惊褰撳墠鐢ㄦ埛鐨勮彍鍗曟潈闄愩�� */
-export function useHomeAccess() {
- const accessStore = useAccessStore();
- const { hasAccessByCodes } = useAccess();
-
- function canQuery(permission: string) {
- return hasAccessByCodes([permission, '*:*:*']);
- }
-
- function canNavigate(name: string) {
- function contains(routes: RouteRecordRaw[]): boolean {
- return routes.some((route) => {
- if (route.meta?.menuVisibleWithForbidden) return false;
- return route.name === name || contains(route.children ?? []);
- });
- }
- return contains(accessStore.accessRoutes);
- }
-
- const canViewHome = computed(() => canQuery('mes:home:query'));
-
- return { canNavigate, canQuery, canViewHome };
-}
diff --git a/src/views/mes/home/data.ts b/src/views/mes/home/data.ts
index 3189c82..e737f33 100644
--- a/src/views/mes/home/data.ts
+++ b/src/views/mes/home/data.ts
@@ -2,6 +2,107 @@
import { MesProWorkOrderStatusEnum } from '@vben/constants';
+/** 棣栭〉鍚勬ā鍧椾緷璧栫殑鑿滃崟锛坮oute.name = 鍚庣鑿滃崟鐨� component_name锛夛細鑿滃崟娌″紑鐨勬ā鍧楁暣鍧椾笉灞曠ず */
+export const HOME_BLOCK_MENUS = {
+ /** 瀹夌伅鍛煎彨 */
+ andon: 'MesProAndonRecord',
+ /** 鍒拌揣閫氱煡 */
+ arrivalNotice: 'MesWmArrivalNotice',
+ /** 鐢熶骇鎶ュ伐 */
+ feedback: 'MesProFeedback',
+ /** 璁惧鍙拌处 */
+ machinery: 'MesDvMachinery',
+ /** 搴撳瓨鐜版湁閲� */
+ materialStock: 'MesWmMaterialStock',
+ /** 宸ュ簭娴佽浆锛堟祦杞崱锛� */
+ processCard: 'MesProCard',
+ /** 鐢熶骇鎺掍骇锛堢敓浜т换鍔★級 */
+ proTask: 'MesProTask',
+ /** 鏉ユ枡妫�楠� */
+ qcIqc: 'MesQcIqc',
+ /** 缁翠慨鍗� */
+ repair: 'MesDvRepair',
+ /** 鐢熶骇璁㈠崟 */
+ workOrder: 'MesProWorkOrder',
+} as const;
+
+/** 鐢熶骇 KPI 鍗$墖渚濊禆鐨勮彍鍗� */
+export const KPI_MENUS: string[] = [
+ HOME_BLOCK_MENUS.workOrder,
+ HOME_BLOCK_MENUS.feedback,
+ HOME_BLOCK_MENUS.machinery,
+];
+
+/** 寰呭姙涓庡紓甯告潯鐩緷璧栫殑鑿滃崟 */
+export const ALERT_MENUS: string[] = [
+ HOME_BLOCK_MENUS.andon,
+ HOME_BLOCK_MENUS.repair,
+ HOME_BLOCK_MENUS.workOrder,
+];
+
+/** 蹇嵎鍏ュ彛锛氬悕绉般�佸浘鏍囥�佸簳鑹蹭笌渚濊禆鐨勮彍鍗� */
+export const HOME_SHORTCUTS: {
+ bgColor: string;
+ icon: string;
+ menu: string;
+ name: string;
+}[] = [
+ {
+ bgColor: '#409EFF',
+ icon: 'lucide:file-text',
+ menu: HOME_BLOCK_MENUS.workOrder,
+ name: '鐢熶骇璁㈠崟',
+ },
+ {
+ bgColor: '#67C23A',
+ icon: 'lucide:edit',
+ menu: HOME_BLOCK_MENUS.feedback,
+ name: '鐢熶骇鎶ュ伐',
+ },
+ {
+ bgColor: '#E6A23C',
+ icon: 'lucide:search',
+ menu: HOME_BLOCK_MENUS.qcIqc,
+ name: '璐ㄩ噺妫�楠�',
+ },
+ {
+ bgColor: '#F56C6C',
+ icon: 'lucide:box',
+ menu: HOME_BLOCK_MENUS.materialStock,
+ name: '搴撳瓨鏌ヨ',
+ },
+ {
+ bgColor: '#7c3aed',
+ icon: 'lucide:cpu',
+ menu: HOME_BLOCK_MENUS.machinery,
+ name: '璁惧绠$悊',
+ },
+ {
+ bgColor: '#0ea5e9',
+ icon: 'lucide:list',
+ menu: HOME_BLOCK_MENUS.proTask,
+ name: '鐢熶骇浠诲姟',
+ },
+ {
+ bgColor: '#14b8a6',
+ icon: 'lucide:truck',
+ menu: HOME_BLOCK_MENUS.arrivalNotice,
+ name: '鍒拌揣閫氱煡',
+ },
+ {
+ bgColor: '#f59e0b',
+ icon: 'lucide:settings-2',
+ menu: HOME_BLOCK_MENUS.repair,
+ name: '璁惧缁翠慨',
+ },
+ {
+ bgColor: '#ec4899',
+ icon: 'lucide:tickets',
+ menu: HOME_BLOCK_MENUS.processCard,
+ name: '娴佽浆鍗�',
+ },
+];
+
/** 棣栭〉姹囨�荤粺璁¢粯璁ゅ�� */
export const defaultSummary: MesHomeApi.Summary = {
andonActiveCount: 0,
diff --git a/src/views/mes/home/index.vue b/src/views/mes/home/index.vue
index 258fbca..da8595f 100644
--- a/src/views/mes/home/index.vue
+++ b/src/views/mes/home/index.vue
@@ -1,7 +1,7 @@
锘�<script lang="ts" setup>
import type { MesHomeApi } from '#/api/mes/home';
-import { onMounted, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
@@ -9,8 +9,14 @@
import { Col, Row } from 'ant-design-vue';
import { getHomeSummary } from '#/api/mes/home';
+import { useHomeAccess } from '#/utils/use-home-access';
-import { defaultSummary } from './data';
+import {
+ ALERT_MENUS,
+ defaultSummary,
+ HOME_BLOCK_MENUS,
+ HOME_SHORTCUTS,
+} from './data';
import AlertPanel from './modules/alert-panel.vue';
import KpiCards from './modules/kpi-cards.vue';
import ProductionTrend from './modules/production-trend.vue';
@@ -19,6 +25,19 @@
const router = useRouter();
const summary = ref<MesHomeApi.Summary>(defaultSummary); // 棣栭〉姹囨�荤粺璁�
+
+// 棣栭〉妯″潡璺熼殢渚ц竟鏍忚彍鍗曪細鑿滃崟娌″紑鐨勬ā鍧楁暣鍧椾笉灞曠ず
+const { canSeeMenu } = useHomeAccess();
+/** 鐢熶骇瓒嬪娍锛堝彇鑷敓浜ф姤宸ワ級 */
+const showTrend = computed(() => canSeeMenu(HOME_BLOCK_MENUS.feedback));
+/** 寰呭姙涓庡紓甯革細浠绘剰涓�鏉$殑鑿滃崟寮�鐫�灏辨覆鏌撹繖涓�鍒� */
+const showAlert = computed(() => ALERT_MENUS.some((menu) => canSeeMenu(menu)));
+/** 璁㈠崟鐘舵�佸垎甯冿紙鍙栬嚜鐢熶骇璁㈠崟锛� */
+const showChart = computed(() => canSeeMenu(HOME_BLOCK_MENUS.workOrder));
+/** 蹇嵎鍏ュ彛锛氫换鎰忎竴涓叆鍙g殑鑿滃崟寮�鐫�灏辨覆鏌撹繖涓�鍒� */
+const showShortcuts = computed(() =>
+ HOME_SHORTCUTS.some((item) => canSeeMenu(item.menu)),
+);
/** 璺宠浆鍒扮洰鏍囬〉闈紙鎸夎矾鐢� name锛� */
function handleNavigate(name: string) {
@@ -40,21 +59,53 @@
<KpiCards :summary="summary" class="mb-4" @navigate="handleNavigate" />
<!-- 绗簩琛岋細鐢熶骇瓒嬪娍 + 寰呭姙寮傚父 -->
- <Row :gutter="16" class="mb-4">
- <Col :lg="16" :md="24" :sm="24" :xl="16" :xs="24" class="mb-4">
+ <Row v-if="showTrend || showAlert" :gutter="16" class="mb-4">
+ <Col
+ v-if="showTrend"
+ :lg="showAlert ? 16 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showAlert ? 16 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<ProductionTrend />
</Col>
- <Col :lg="8" :md="24" :sm="24" :xl="8" :xs="24" class="mb-4">
+ <Col
+ v-if="showAlert"
+ :lg="showTrend ? 8 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showTrend ? 8 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<AlertPanel :summary="summary" @navigate="handleNavigate" />
</Col>
</Row>
<!-- 绗笁琛岋細璁㈠崟鍒嗗竷 + 蹇嵎鍏ュ彛 -->
- <Row :gutter="16">
- <Col :lg="12" :md="24" :sm="24" :xl="12" :xs="24" class="mb-4">
+ <Row v-if="showChart || showShortcuts" :gutter="16">
+ <Col
+ v-if="showChart"
+ :lg="showShortcuts ? 12 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showShortcuts ? 12 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<WorkOrderChart />
</Col>
- <Col :lg="12" :md="24" :sm="24" :xl="12" :xs="24" class="mb-4">
+ <Col
+ v-if="showShortcuts"
+ :lg="showChart ? 12 : 24"
+ :md="24"
+ :sm="24"
+ :xl="showChart ? 12 : 24"
+ :xs="24"
+ class="mb-4"
+ >
<Shortcuts @navigate="handleNavigate" />
</Col>
</Row>
diff --git a/src/views/mes/home/modules/alert-panel.vue b/src/views/mes/home/modules/alert-panel.vue
index 8584cce..9128c9c 100644
--- a/src/views/mes/home/modules/alert-panel.vue
+++ b/src/views/mes/home/modules/alert-panel.vue
@@ -7,6 +7,10 @@
import { Badge, Card } from 'ant-design-vue';
+import { useHomeAccess } from '#/utils/use-home-access';
+
+import { HOME_BLOCK_MENUS } from '../data';
+
defineOptions({ name: 'MesHomeAlertPanel' });
const props = defineProps<{
@@ -17,37 +21,41 @@
navigate: [name: string];
}>();
-/** 寰呭姙鎻愰啋鍒楄〃锛氭爣绛俱�佹弿杩般�佸浘鏍囥�佺洰鏍囪矾鐢卞悕绉般�佹暟閲� */
-const alertItems = computed(() => [
- {
- count: props.summary.andonActiveCount,
- desc: '鏈缃殑瀹夌伅鍛煎彨',
- icon: 'lucide:bell-ring',
- iconClass: 'bg-red-50 text-red-500',
- label: '瀹夌伅鎶ヨ',
- routeName: 'MesProAndonRecord',
- },
- {
- count: props.summary.repairActiveCount,
- desc: '寰呭鐞嗙殑缁翠慨璁㈠崟',
- icon: 'lucide:wrench',
- iconClass: 'bg-orange-50 text-orange-500',
- label: '璁惧缁翠慨',
- routeName: 'MesDvRepair',
- },
- {
- count: props.summary.workOrderPrepareCount,
- desc: '鑽夌鐘舵�佺殑鐢熶骇璁㈠崟',
- icon: 'lucide:clipboard-list',
- iconClass: 'bg-blue-50 text-blue-500',
- label: '寰呮帓浜ц鍗�',
- routeName: 'MesProWorkOrder',
- },
-]);
+const { canSeeMenu } = useHomeAccess();
+
+/** 寰呭姙鎻愰啋鍒楄〃锛氭爣绛俱�佹弿杩般�佸浘鏍囥�佺洰鏍囪矾鐢卞悕绉般�佹暟閲忥紱鑿滃崟娌″紑鐨勬潯鐩笉灞曠ず */
+const alertItems = computed(() =>
+ [
+ {
+ count: props.summary.andonActiveCount,
+ desc: '鏈缃殑瀹夌伅鍛煎彨',
+ icon: 'lucide:bell-ring',
+ iconClass: 'bg-red-50 text-red-500',
+ label: '瀹夌伅鎶ヨ',
+ routeName: HOME_BLOCK_MENUS.andon,
+ },
+ {
+ count: props.summary.repairActiveCount,
+ desc: '寰呭鐞嗙殑缁翠慨璁㈠崟',
+ icon: 'lucide:wrench',
+ iconClass: 'bg-orange-50 text-orange-500',
+ label: '璁惧缁翠慨',
+ routeName: HOME_BLOCK_MENUS.repair,
+ },
+ {
+ count: props.summary.workOrderPrepareCount,
+ desc: '鑽夌鐘舵�佺殑鐢熶骇璁㈠崟',
+ icon: 'lucide:clipboard-list',
+ iconClass: 'bg-blue-50 text-blue-500',
+ label: '寰呮帓浜ц鍗�',
+ routeName: HOME_BLOCK_MENUS.workOrder,
+ },
+ ].filter((item) => canSeeMenu(item.routeName)),
+);
</script>
<template>
- <Card title="寰呭姙涓庡紓甯�" class="h-full">
+ <Card v-if="alertItems.length" title="寰呭姙涓庡紓甯�" class="h-full">
<div class="flex flex-col">
<div
v-for="item in alertItems"
diff --git a/src/views/mes/home/modules/kpi-cards.vue b/src/views/mes/home/modules/kpi-cards.vue
index f104479..e6b7c5f 100644
--- a/src/views/mes/home/modules/kpi-cards.vue
+++ b/src/views/mes/home/modules/kpi-cards.vue
@@ -8,6 +8,10 @@
import { Card, Col, Divider, Row } from 'ant-design-vue';
+import { useHomeAccess } from '#/utils/use-home-access';
+
+import { HOME_BLOCK_MENUS } from '../data';
+
defineOptions({ name: 'MesHomeKpiCards' });
const props = defineProps<{
@@ -17,6 +21,9 @@
const emit = defineEmits<{
navigate: [name: string];
}>();
+
+/** 鑿滃崟娌″紑鐨勬ā鍧楋紝瀵瑰簲 KPI 鍗′笉灞曠ず */
+const { canSeeMenu } = useHomeAccess();
/** 鏄惁鏈夎川閲忔暟鎹紙鍚堟牸鍝� + 涓嶈壇鍝� > 0锛� */
const hasQualityData = computed(
@@ -40,10 +47,18 @@
<template>
<Row :gutter="16">
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col
+ v-if="canSeeMenu(HOME_BLOCK_MENUS.workOrder)"
+ :lg="6"
+ :md="12"
+ :sm="12"
+ :xl="6"
+ :xs="24"
+ class="mb-4"
+ >
<Card
class="kpi-card cursor-pointer transition-all hover:-translate-y-1 hover:shadow-lg"
- @click="emit('navigate', 'MesProWorkOrder')"
+ @click="emit('navigate', HOME_BLOCK_MENUS.workOrder)"
>
<div class="flex items-center gap-4">
<div
@@ -71,10 +86,18 @@
</div>
</Card>
</Col>
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col
+ v-if="canSeeMenu(HOME_BLOCK_MENUS.feedback)"
+ :lg="6"
+ :md="12"
+ :sm="12"
+ :xl="6"
+ :xs="24"
+ class="mb-4"
+ >
<Card
class="kpi-card cursor-pointer transition-all hover:-translate-y-1 hover:shadow-lg"
- @click="emit('navigate', 'MesProFeedback')"
+ @click="emit('navigate', HOME_BLOCK_MENUS.feedback)"
>
<div class="flex items-center gap-4">
<div
@@ -100,10 +123,18 @@
</div>
</Card>
</Col>
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col
+ v-if="canSeeMenu(HOME_BLOCK_MENUS.feedback)"
+ :lg="6"
+ :md="12"
+ :sm="12"
+ :xl="6"
+ :xs="24"
+ class="mb-4"
+ >
<Card
class="kpi-card cursor-pointer transition-all hover:-translate-y-1 hover:shadow-lg"
- @click="emit('navigate', 'MesProFeedback')"
+ @click="emit('navigate', HOME_BLOCK_MENUS.feedback)"
>
<div class="flex items-center gap-4">
<div
@@ -135,10 +166,18 @@
</div>
</Card>
</Col>
- <Col :lg="6" :md="12" :sm="12" :xl="6" :xs="24" class="mb-4">
+ <Col
+ v-if="canSeeMenu(HOME_BLOCK_MENUS.machinery)"
+ :lg="6"
+ :md="12"
+ :sm="12"
+ :xl="6"
+ :xs="24"
+ class="mb-4"
+ >
<Card
class="kpi-card cursor-pointer transition-all hover:-translate-y-1 hover:shadow-lg"
- @click="emit('navigate', 'MesDvMachinery')"
+ @click="emit('navigate', HOME_BLOCK_MENUS.machinery)"
>
<div class="flex items-center gap-4">
<div
diff --git a/src/views/mes/home/modules/production-trend.vue b/src/views/mes/home/modules/production-trend.vue
index 4441514..9a6c21d 100644
--- a/src/views/mes/home/modules/production-trend.vue
+++ b/src/views/mes/home/modules/production-trend.vue
@@ -1,7 +1,7 @@
<script lang="ts" setup>
import type { EchartsUIType } from '@vben/plugins/echarts';
-import { onMounted, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
@@ -9,16 +9,24 @@
import { getProductionTrend } from '#/api/mes/home';
+import { useHomeAccess } from '#/utils/use-home-access';
+
import { getProductionTrendChartOptions } from '../chart-options';
+import { HOME_BLOCK_MENUS } from '../data';
defineOptions({ name: 'MesHomeProductionTrend' });
const trendDays = ref(7); // 褰撳墠閫変腑鐨勫ぉ鏁拌寖鍥�
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
+const { canSeeMenu } = useHomeAccess();
+
+/** 鐢熶骇瓒嬪娍鍙栬嚜鐢熶骇鎶ュ伐锛屾姤宸ヨ彍鍗曟病寮�灏变笉灞曠ず銆佷笉璇锋眰 */
+const showTrend = computed(() => canSeeMenu(HOME_BLOCK_MENUS.feedback));
/** 鍔犺浇鐢熶骇瓒嬪娍鏁版嵁骞舵覆鏌撳浘琛� */
async function loadData() {
+ if (!showTrend.value) return;
const data = await getProductionTrend(trendDays.value);
const dates = data.map((d) => d.date.slice(5));
const quantities = data.map((d) => d.quantity);
@@ -40,7 +48,7 @@
</script>
<template>
- <Card title="鐢熶骇瓒嬪娍" class="h-full">
+ <Card v-if="showTrend" title="鐢熶骇瓒嬪娍" class="h-full">
<template #extra>
<RadioGroup
v-model:value="trendDays"
diff --git a/src/views/mes/home/modules/shortcuts.vue b/src/views/mes/home/modules/shortcuts.vue
index 09a6c38..f1e81a9 100644
--- a/src/views/mes/home/modules/shortcuts.vue
+++ b/src/views/mes/home/modules/shortcuts.vue
@@ -1,7 +1,13 @@
锘�<script lang="ts" setup>
+import { computed } from 'vue';
+
import { IconifyIcon } from '@vben/icons';
import { Card, Col, Row } from 'ant-design-vue';
+
+import { useHomeAccess } from '#/utils/use-home-access';
+
+import { HOME_SHORTCUTS } from '../data';
defineOptions({ name: 'MesHomeShortcuts' });
@@ -9,72 +15,21 @@
navigate: [name: string];
}>();
-/** 蹇嵎鍏ュ彛鍒楄〃锛�3脳3 缃戞牸甯冨眬涓庤鍗曠姸鎬佸垎甯冮潰鏉跨瓑楂� */
-const shortcuts = [
- {
- bgColor: '#409EFF',
- icon: 'lucide:file-text',
- name: '鐢熶骇璁㈠崟',
- routeName: 'MesProWorkOrder',
- },
- {
- bgColor: '#67C23A',
- icon: 'lucide:edit',
- name: '鐢熶骇鎶ュ伐',
- routeName: 'MesProFeedback',
- },
- {
- bgColor: '#E6A23C',
- icon: 'lucide:search',
- name: '璐ㄩ噺妫�楠�',
- routeName: 'MesQcIqc',
- },
- {
- bgColor: '#F56C6C',
- icon: 'lucide:box',
- name: '搴撳瓨鏌ヨ',
- routeName: 'MesWmMaterialStock',
- },
- {
- bgColor: '#7c3aed',
- icon: 'lucide:cpu',
- name: '璁惧绠$悊',
- routeName: 'MesDvMachinery',
- },
- {
- bgColor: '#0ea5e9',
- icon: 'lucide:list',
- name: '鐢熶骇浠诲姟',
- routeName: 'MesProTask',
- },
- {
- bgColor: '#14b8a6',
- icon: 'lucide:truck',
- name: '鍒拌揣閫氱煡',
- routeName: 'MesWmArrivalNotice',
- },
- {
- bgColor: '#f59e0b',
- icon: 'lucide:settings-2',
- name: '璁惧缁翠慨',
- routeName: 'MesDvRepair',
- },
- {
- bgColor: '#ec4899',
- icon: 'lucide:tickets',
- name: '娴佽浆鍗�',
- routeName: 'MesProCard',
- },
-];
+const { canSeeMenu } = useHomeAccess();
+
+/** 蹇嵎鍏ュ彛鍒楄〃锛�3脳3 缃戞牸甯冨眬涓庤鍗曠姸鎬佸垎甯冮潰鏉跨瓑楂橈紱鑿滃崟娌″紑鐨勪笉灞曠ず */
+const shortcuts = computed(() =>
+ HOME_SHORTCUTS.filter((item) => canSeeMenu(item.menu)),
+);
</script>
<template>
- <Card title="蹇嵎鍏ュ彛" class="h-full">
+ <Card v-if="shortcuts.length" title="蹇嵎鍏ュ彛" class="h-full">
<Row :gutter="16">
<Col v-for="item in shortcuts" :key="item.name" :span="8" class="mb-4">
<div
class="hover:bg-accent flex cursor-pointer flex-col items-center gap-2 rounded-lg py-3 transition-all hover:-translate-y-0.5"
- @click="emit('navigate', item.routeName)"
+ @click="emit('navigate', item.menu)"
>
<div
class="flex size-12 items-center justify-center rounded-xl text-white"
diff --git a/src/views/mes/home/modules/work-order-chart.vue b/src/views/mes/home/modules/work-order-chart.vue
index f96be87..8988db8 100644
--- a/src/views/mes/home/modules/work-order-chart.vue
+++ b/src/views/mes/home/modules/work-order-chart.vue
@@ -1,7 +1,7 @@
锘�<script lang="ts" setup>
import type { EchartsUIType } from '@vben/plugins/echarts';
-import { onMounted, ref } from 'vue';
+import { computed, onMounted, ref } from 'vue';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
@@ -9,16 +9,23 @@
import { getWorkOrderStatusDistribution } from '#/api/mes/home';
+import { useHomeAccess } from '#/utils/use-home-access';
+
import { getWorkOrderStatusChartOptions } from '../chart-options';
-import { WORK_ORDER_STATUS_COLOR_MAP } from '../data';
+import { HOME_BLOCK_MENUS, WORK_ORDER_STATUS_COLOR_MAP } from '../data';
defineOptions({ name: 'MesHomeWorkOrderChart' });
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
+const { canSeeMenu } = useHomeAccess();
+
+/** 鑿滃崟娌″紑灏变笉灞曠ず銆佷笉璇锋眰 */
+const showChart = computed(() => canSeeMenu(HOME_BLOCK_MENUS.workOrder));
/** 鍔犺浇璁㈠崟鐘舵�佸垎甯冩暟鎹苟娓叉煋楗煎浘 */
async function loadData() {
+ if (!showChart.value) return;
const data = await getWorkOrderStatusDistribution();
const chartData = data.map((d) => ({
itemStyle: { color: WORK_ORDER_STATUS_COLOR_MAP[d.status] || '#409EFF' },
@@ -34,7 +41,7 @@
</script>
<template>
- <Card title="璁㈠崟鐘舵�佸垎甯�" class="h-full">
+ <Card v-if="showChart" title="璁㈠崟鐘舵�佸垎甯�" class="h-full">
<EchartsUI ref="chartRef" class="h-[280px] w-full" />
</Card>
</template>
--
Gitblit v1.9.3