Prechádzať zdrojové kódy

feat: 补充权限信息,补充空状态显示,补充空内容显示。

lixuan 3 týždňov pred
rodič
commit
688ed760a4

+ 2 - 4
apps/web-velofex/src/api/core/menu.ts

@@ -1,4 +1,4 @@
-import type { RouteRecordStringComponent } from '@vben/types';
+// import type { RouteRecordStringComponent } from '@vben/types';
 
 import { requestClient } from '#/api/request';
 
@@ -6,7 +6,5 @@ import { requestClient } from '#/api/request';
  * 获取用户所有菜单
  */
 export async function getAllMenusApi() {
-  return requestClient.get<RouteRecordStringComponent[]>(
-    '/api/menu/leftMenuList',
-  );
+  return requestClient.post('/api/menu/leftMenuList');
 }

BIN
apps/web-velofex/src/assets/image/empty.png


BIN
apps/web-velofex/src/assets/image/jurisdiction.png


+ 5 - 1
apps/web-velofex/src/locales/langs/en-US/page.json

@@ -54,7 +54,11 @@
       "value":"Are you sure you want to log out?"
     },
     "logOutOK":"Logout successful!",
-    "changeInformation":"Change Information"
+    "changeInformation":"Change Information",
+    "emptyContent":"No content available",
+    "noPermission":"No permission to view",
+    "noPhone":"No phone number available",
+    "noEmail":"No email available"
   },
   "dashboard": {
     "analytics": "Analytics",

+ 5 - 1
apps/web-velofex/src/locales/langs/zh-CN/page.json

@@ -54,7 +54,11 @@
       "value":"确定要退出登录吗?"
     },
     "logOutOK":"退出成功!",
-    "changeInformation":"修改个人信息"
+    "changeInformation":"修改个人信息",
+    "emptyContent":"暂无内容",
+    "noPermission":"暂无查看权限",
+    "noPhone":"暂无手机号",
+    "noEmail":"暂无邮箱地址"
   },
   "dashboard": {
     "title": "概览",

+ 2 - 0
apps/web-velofex/src/views/dashboard/enterprise-customers/index.vue

@@ -127,6 +127,7 @@ async function fetchEnterpriseCustomers() {
       totalPage.value = result.result.totalPages;
       totalCount.value = result.result.totalCount;
     }
+    loading.value = false;
   } catch {}
 }
 
@@ -144,6 +145,7 @@ async function deleteCustomer(item: any) {
       fetchEnterpriseCustomers();
       message.success($t('enterpriseCustomers.deleteSuccess'));
     }
+    loading.value = false;
   } catch {}
 }
 

+ 35 - 6
apps/web-velofex/src/views/dashboard/home/application-management.vue

@@ -9,6 +9,11 @@ import { $t } from '@/locales';
 import { getMyApplicationListApi, type UserApi } from '#/api';
 import { useLoginModalStore } from '#/store';
 
+interface Props {
+  jurisdiction: boolean;
+}
+
+const props = defineProps<Props>();
 const router = useRouter();
 const userStore = useUserStore();
 const isLogin = computed(() => !!userStore.userInfo);
@@ -89,19 +94,43 @@ watch(
       {{ $t('homeModule.applicationManagementIntroduction') }}
     </p>
 
-    <div v-if="isLogin" class="mt-[38px] flex flex-wrap gap-[18px]">
+    <div v-else-if="props.jurisdiction && isLogin" class="mt-[38px]">
+      <div v-if="applicationList.length > 0" class="flex flex-wrap gap-[18px]">
+        <div
+          v-for="(item, index) in applicationList"
+          :key="index"
+          class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        >
+          <img
+            :src="`/File/Download?fileId=${item.imgPhotoFileId}`"
+            alt=""
+            class="h-[24px] w-auto object-contain"
+          />
+        </div>
+      </div>
       <div
-        v-for="(item, index) in applicationList"
-        :key="index"
-        class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        v-else
+        class="mx-auto mt-[-20px] flex flex-col items-center justify-center text-center"
       >
         <img
-          :src="`/File/Download?fileId=${item.imgPhotoFileId}`"
           alt=""
-          class="h-[24px] w-auto object-contain"
+          class="block h-[80px] w-[85px]"
+          src="@/assets/image/jurisdiction.png"
         />
+        {{ $t('auth.emptyContent') }}
       </div>
     </div>
+    <div
+      v-else
+      class="mt-[10px] flex flex-col items-center justify-center text-center"
+    >
+      <img
+        alt=""
+        class="block h-[80px] w-[85px]"
+        src="@/assets/image/empty.png"
+      />
+      {{ $t('auth.noPermission') }}
+    </div>
   </div>
 </template>
 

+ 37 - 9
apps/web-velofex/src/views/dashboard/home/delivery-partners.vue

@@ -9,11 +9,14 @@ import { $t } from '@/locales';
 import { getDeliveryPartnersApi, type UserApi } from '#/api';
 import { useLoginModalStore } from '#/store';
 
+interface Props {
+  jurisdiction: boolean;
+}
+
+const props = defineProps<Props>();
 const router = useRouter();
 const loginModalStore = useLoginModalStore();
-
 const userStore = useUserStore();
-
 const isLogin = computed(() => !!userStore.userInfo);
 
 function handleNavigate() {
@@ -74,6 +77,7 @@ watch(
         <div class="text-xs text-[#9A9BA3]">Delivery Partners</div>
       </div>
       <img
+        v-if="props.jurisdiction"
         alt="more"
         class="h-[29px] w-[29px] cursor-pointer"
         src="@/assets/image/home-more.png"
@@ -87,16 +91,40 @@ watch(
       {{ $t('homeModule.deliveryPartnersIntroduction') }}
     </p>
 
-    <div v-if="isLogin" class="mt-[63px] flex gap-[18px]">
+    <div v-if="props.jurisdiction && isLogin" class="mt-[63px]">
+      <div v-if="deliveryPartnersList.length > 0" class="flex gap-[18px]">
+        <img
+          v-for="index in 4"
+          :key="index"
+          :src="`/src/assets/image/user${index}.png`"
+          :style="{ marginLeft: index !== 1 ? '-35px' : '0' }"
+          :text="index"
+          alt=""
+          class="h-[46px] w-[46px]"
+        />
+      </div>
+      <div
+        v-else
+        class="mx-auto mt-[-20px] flex flex-col items-center justify-center text-center"
+      >
+        <img
+          alt=""
+          class="block h-[80px] w-[85px]"
+          src="@/assets/image/jurisdiction.png"
+        />
+        {{ $t('auth.emptyContent') }}
+      </div>
+    </div>
+    <div
+      v-else
+      class="mt-[10px] flex flex-col items-center justify-center text-center"
+    >
       <img
-        v-for="index in 4"
-        :key="index"
-        :src="`/src/assets/image/user${index}.png`"
-        :style="{ marginLeft: index !== 1 ? '-35px' : '0' }"
-        :text="index"
         alt=""
-        class="h-[46px] w-[46px]"
+        class="block h-[80px] w-[85px]"
+        src="@/assets/image/empty.png"
       />
+      {{ $t('auth.noPermission') }}
     </div>
   </div>
 </template>

+ 36 - 6
apps/web-velofex/src/views/dashboard/home/enterprise-customers.vue

@@ -9,6 +9,11 @@ import { $t } from '@/locales';
 import { getEnterpriseCustomersApi } from '#/api';
 import { useLoginModalStore } from '#/store';
 
+interface Props {
+  jurisdiction: boolean;
+}
+
+const props = defineProps<Props>();
 const userStore = useUserStore();
 const isLogin = computed(() => !!userStore.userInfo);
 const router = useRouter();
@@ -63,6 +68,7 @@ watch(
         <div class="text-xs text-[#9A9BA3]">Enterprise Customers</div>
       </div>
       <img
+        v-if="props.jurisdiction"
         alt="more"
         class="h-[29px] w-[29px] cursor-pointer"
         src="@/assets/image/home-more.png"
@@ -75,19 +81,43 @@ watch(
     >
       {{ $t('homeModule.enterpriseCustomersIntroduction') }}
     </p>
-    <div v-else class="mt-[38px] flex flex-wrap gap-[18px]">
+    <div v-else-if="props.jurisdiction && isLogin" class="mt-[38px]">
+      <div v-if="customerList.length > 0" class="flex flex-wrap gap-[18px]">
+        <div
+          v-for="(item, index) in customerList"
+          :key="index"
+          class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        >
+          <img
+            :src="`/File/Download?fileId=${item.imgPhotoFileId}`"
+            alt=""
+            class="h-[24px] w-auto object-contain"
+          />
+        </div>
+      </div>
       <div
-        v-for="(item, index) in customerList"
-        :key="index"
-        class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        v-else
+        class="mt-[-28px] flex w-full flex-col items-center justify-center text-center"
       >
         <img
-          :src="`/File/Download?fileId=${item.imgPhotoFileId}`"
           alt=""
-          class="h-[24px] w-auto object-contain"
+          class="block h-[80px] w-[85px]"
+          src="@/assets/image/jurisdiction.png"
         />
+        {{ $t('auth.emptyContent') }}
       </div>
     </div>
+    <div
+      v-else
+      class="mt-[10px] flex flex-col items-center justify-center text-center"
+    >
+      <img
+        alt=""
+        class="block h-[80px] w-[85px]"
+        src="@/assets/image/empty.png"
+      />
+      {{ $t('auth.noPermission') }}
+    </div>
   </div>
 </template>
 

+ 55 - 18
apps/web-velofex/src/views/dashboard/home/index.vue

@@ -1,38 +1,75 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+
+import { useUserStore } from '@vben/stores';
+
+import { Col, Row } from 'antdv-next';
+
+import { getAllMenusApi } from '#/api';
+
+import ApplicationManagement from './application-management.vue';
+import DeliveryPartners from './delivery-partners.vue';
+import EnterpriseCustomers from './enterprise-customers.vue';
+import ProductList from './product-list.vue';
+import SalesPartners from './sales-partners.vue';
+import UserInfo from './user-info.vue';
+
+const userStore = useUserStore();
+
+const isLogin = computed(() => !!userStore.userInfo);
+const menus = ref<any[]>([]);
+const salesPartnersShow = ref(true);
+const enterpriseCustomersShow = ref(true);
+const applicationManagementShow = ref(true);
+const deliveryPartnersShow = ref(true);
+
+async function fetchMenus() {
+  try {
+    const result = await getAllMenusApi();
+    menus.value = result.result.children;
+    const menuCodes = new Set(menus.value.map((menu) => menu.code));
+    salesPartnersShow.value = menuCodes.has('Sys_Menu_Partner');
+    enterpriseCustomersShow.value = menuCodes.has('Sys_Menu_EnterClient');
+    applicationManagementShow.value = menuCodes.has('Sys_Menu_Project');
+    deliveryPartnersShow.value = menuCodes.has('Sys_Menu_User');
+  } catch (error) {
+    console.error('获取菜单失败:', error);
+  }
+}
+
+watch(
+  () => isLogin.value,
+  (newValue) => {
+    if (newValue) {
+      fetchMenus();
+    }
+  },
+  { immediate: true },
+);
+</script>
+
 <template>
   <div>
     <Row :gutter="[30, 25]">
       <Col :span="9">
-        <SalesPartners />
+        <SalesPartners :jurisdiction="salesPartnersShow" />
       </Col>
       <Col :span="9">
-        <EnterpriseCustomers />
+        <EnterpriseCustomers :jurisdiction="enterpriseCustomersShow" />
       </Col>
       <Col :span="6">
         <UserInfo />
       </Col>
 
       <Col :span="18">
-        <ApplicationManagement />
+        <ApplicationManagement :jurisdiction="applicationManagementShow" />
       </Col>
       <Col :span="6">
-        <DeliveryPartners />
+        <DeliveryPartners :jurisdiction="deliveryPartnersShow" />
       </Col>
     </Row>
     <ProductList />
   </div>
 </template>
 
-<script setup lang="ts">
-import { Row, Col } from 'antdv-next';
-import SalesPartners from './sales-partners.vue';
-import EnterpriseCustomers from './enterprise-customers.vue';
-import ApplicationManagement from './application-management.vue';
-import ProductList from './product-list.vue';
-import UserInfo from './user-info.vue';
-import DeliveryPartners from './delivery-partners.vue';
-
-</script>
-
-<style scoped>
-
-</style>
+<style scoped></style>

+ 36 - 6
apps/web-velofex/src/views/dashboard/home/sales-partners.vue

@@ -9,6 +9,11 @@ import { $t } from '@/locales';
 import { getPartnersListApi, type UserApi } from '#/api';
 import { useLoginModalStore } from '#/store';
 
+interface Props {
+  jurisdiction: boolean;
+}
+
+const props = defineProps<Props>();
 const userStore = useUserStore();
 const isLogin = computed(() => !!userStore.userInfo);
 const router = useRouter();
@@ -66,6 +71,7 @@ watch(
         <div class="text-xs text-[#9A9BA3]">Sales Partners</div>
       </div>
       <img
+        v-if="props.jurisdiction"
         alt="more"
         class="h-[29px] w-[29px] cursor-pointer"
         src="@/assets/image/home-more.png"
@@ -78,19 +84,43 @@ watch(
     >
       {{ $t('homeModule.salesPartnersIntroduction') }}
     </p>
-    <div v-else class="mt-[38px] flex flex-wrap gap-[18px]">
+    <div v-else-if="props.jurisdiction && isLogin" class="mt-[38px]">
+      <div v-if="partnerList.length > 0" class="flex flex-wrap gap-[18px]">
+        <div
+          v-for="partner in partnerList"
+          :key="partner.id"
+          class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        >
+          <img
+            :src="`/File/Download?fileId=${partner.imgPhotoFileId}`"
+            alt=""
+            class="h-[24px] w-auto object-contain"
+          />
+        </div>
+      </div>
       <div
-        v-for="partner in partnerList"
-        :key="partner.id"
-        class="flex h-[37px] cursor-pointer items-center rounded-[11px] bg-[#fff] p-[6px_10px] shadow-md"
+        v-else
+        class="mt-[10px] flex flex-col items-center justify-center text-center"
       >
         <img
-          :src="`/File/Download?fileId=${partner.imgPhotoFileId}`"
           alt=""
-          class="h-[24px] w-auto object-contain"
+          class="block h-[80px] w-[85px]"
+          src="@/assets/image/jurisdiction.png"
         />
+        {{ $t('auth.emptyContent') }}
       </div>
     </div>
+    <div
+      v-else
+      class="mt-[10px] flex flex-col items-center justify-center text-center"
+    >
+      <img
+        alt=""
+        class="block h-[80px] w-[85px]"
+        src="@/assets/image/empty.png"
+      />
+      {{ $t('auth.noPermission') }}
+    </div>
   </div>
 </template>
 

+ 7 - 3
apps/web-velofex/src/views/dashboard/home/user-info.vue

@@ -22,6 +22,10 @@ function handleLogout() {
 function openLogin() {
   loginModalStore.open();
 }
+
+function handleEditProfile() {
+  window.open('/Views/Home/userSet.html', '_blank');
+}
 </script>
 
 <template>
@@ -76,11 +80,11 @@ function openLogin() {
       </h2>
       <p class="mb-[4px] flex w-[249px] items-center gap-2 text-[12px] text-xs">
         <img class="h-[12px] w-[12px]" src="@/assets/image/phone.png" />
-        {{ userStore.userInfo?.cellPhone }}
+        {{ userStore.userInfo?.cellPhone || $t('auth.noPhone') }}
       </p>
       <p class="flex w-[249px] items-center gap-2 text-[12px] text-xs">
         <img class="h-[8.77px] w-[14.61px]" src="@/assets/image/email.png" />
-        {{ userStore.userInfo?.email }}
+        {{ userStore.userInfo?.email || $t('auth.noEmail') }}
       </p>
     </div>
     <div
@@ -92,7 +96,7 @@ function openLogin() {
         class="h-[12.95px] w-[12.95px]"
         src="@/assets/image/edit.png"
       />
-      <span>{{ $t('homeModule.editProfile') }}</span>
+      <span @click="handleEditProfile">{{ $t('homeModule.editProfile') }}</span>
     </div>
   </div>
 </template>