From 94d91d89fd5e3a641e77629ac60ea5d7e1a6801f Mon Sep 17 00:00:00 2001
From: houzhongjian <houzhongyi@126.com>
Date: 星期三, 27 十一月 2024 09:53:37 +0800
Subject: [PATCH] 1、修改首页 2、修改租户套餐页面 3、修改logo图标 4、点击左上角平台名称和logo,展示所有菜单等

---
 /dev/null                                            |    0 
 src/views/system/tenantPackage/TenantPackageForm.vue |   21 +++
 src/views/report/drag/index.vue                      |   13 +
 src/hooks/web/useCache.ts                            |   16 ++
 index.html                                           |    4 
 src/assets/imgs/logo.png                             |    0 
 src/api/system/tenantPackage/index.ts                |    3 
 src/store/modules/user.ts                            |    1 
 src/layout/components/Logo/src/Logo.vue              |   25 +++
 src/views/Home/Index.vue                             |  104 ++++++++++----
 src/views/system/tenantPackage/index.vue             |  166 ++++++++++++++++++-----
 src/views/micro/index.vue                            |   26 +--
 12 files changed, 294 insertions(+), 85 deletions(-)

diff --git a/index.html b/index.html
index 0d9deba..c3d9097 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
+    <link rel="icon" href="/src/assets/imgs/logo.png" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <meta
@@ -136,7 +136,7 @@
       <div class="app-loading">
         <div class="app-loading-wrap">
           <div class="app-loading-title">
-            <img src="/logo.gif" class="app-loading-logo" alt="Logo" />
+            <img src="/src/assets/imgs/logo.png" class="app-loading-logo" alt="Logo" />
             <div class="app-loading-title">%VITE_APP_TITLE%</div>
           </div>
           <div class="app-loading-item">
diff --git a/public/favicon.ico b/public/favicon.ico
deleted file mode 100644
index 5a7de08..0000000
--- a/public/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/public/logo.gif b/public/logo.gif
deleted file mode 100644
index fdbd32c..0000000
--- a/public/logo.gif
+++ /dev/null
Binary files differ
diff --git a/src/api/system/tenantPackage/index.ts b/src/api/system/tenantPackage/index.ts
index e01375a..fdf9a5b 100644
--- a/src/api/system/tenantPackage/index.ts
+++ b/src/api/system/tenantPackage/index.ts
@@ -4,6 +4,9 @@
   id: number
   name: string
   status: number
+  icon: string
+  labels: string
+  description: string
   remark: string
   creator: string
   updater: string
diff --git a/src/assets/imgs/logo.png b/src/assets/imgs/logo.png
index 4017d80..f55aafb 100644
--- a/src/assets/imgs/logo.png
+++ b/src/assets/imgs/logo.png
Binary files differ
diff --git a/src/hooks/web/useCache.ts b/src/hooks/web/useCache.ts
index 4f39f30..f6b2bd1 100644
--- a/src/hooks/web/useCache.ts
+++ b/src/hooks/web/useCache.ts
@@ -37,3 +37,19 @@
   wsCache.delete(CACHE_KEY.ROLE_ROUTERS)
   // 注意,不要清理 LoginForm 登录表单
 }
+
+export const useSessionCache = (type: CacheType = 'sessionStorage') => {
+  const wsSessionCache: WebStorageCache = new WebStorageCache({
+    storage: type
+  })
+
+  return {
+    wsSessionCache
+  }
+}
+
+export const deleteUserSessionCache = () => {
+  const { wsSessionCache } = useSessionCache()
+  wsSessionCache.delete(CACHE_KEY.ROLE_ROUTERS)
+  // 注意,不要清理 用户和 LoginForm 登录表单
+}
diff --git a/src/layout/components/Logo/src/Logo.vue b/src/layout/components/Logo/src/Logo.vue
index 2d1cfb6..98b17c3 100644
--- a/src/layout/components/Logo/src/Logo.vue
+++ b/src/layout/components/Logo/src/Logo.vue
@@ -1,8 +1,14 @@
 <script lang="ts" setup>
 import { computed, onMounted, ref, unref, watch } from 'vue'
 import { useAppStore } from '@/store/modules/app'
+import { useUserStoreWithOut } from '@/store/modules/user'
+import { usePermissionStoreWithOut } from '@/store/modules/permission'
 import { useDesign } from '@/hooks/web/useDesign'
-import * as authUtil from "@/utils/auth";
+import {isRelogin} from "@/config/axios/service";
+import router from "@/router";
+import type {RouteRecordRaw} from "vue-router";
+import {CACHE_KEY, useCache} from "@/hooks/web/useCache";
+const { wsCache } = useCache()
 
 defineOptions({ name: 'Logo' })
 
@@ -59,6 +65,22 @@
     }
   }
 )
+
+/** 刷新所有菜单权限 */
+const gotoHome = async () => {
+  const userStore = useUserStoreWithOut()
+  const permissionStore = usePermissionStoreWithOut()
+  isRelogin.show = true
+  wsCache.set(CACHE_KEY.USER, null)
+  await userStore.setUserInfoAction()
+  isRelogin.show = false
+  // 后端过滤菜单
+  await permissionStore.generateRoutes()
+  permissionStore.getAddRouters.forEach((route) => {
+    router.addRoute(route as unknown as RouteRecordRaw) // 动态添加可访问路由表
+  })
+}
+
 </script>
 
 <template>
@@ -69,6 +91,7 @@
         layout !== 'classic' ? `${prefixCls}__Top` : '',
         'flex !h-[var(--logo-height)] items-center cursor-pointer pl-8px relative decoration-none overflow-hidden'
       ]"
+      @click="gotoHome"
       :to="homePath"
     >
       <img
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index b386180..1e8ae63 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -61,6 +61,7 @@
       this.roles = userInfo.roles
       this.user = userInfo.user
       this.isSetUser = true
+      console.log(userInfo.menus)
       wsCache.set(CACHE_KEY.USER, userInfo)
       wsCache.set(CACHE_KEY.ROLE_ROUTERS, userInfo.menus)
     },
diff --git a/src/views/Home/Index.vue b/src/views/Home/Index.vue
index 822f800..8150679 100644
--- a/src/views/Home/Index.vue
+++ b/src/views/Home/Index.vue
@@ -1,13 +1,20 @@
 <template>
-  <div>
-    <h1>IAILAB 平台主页</h1>
+  <div id="title">
+    <span>工业互联网平台</span>
   </div>
   <el-skeleton :loading="loading" animated>
-    <div id="app" v-for="(item, index) in appList" :key="`dynamics-${index}`">
-      <div class="card" @click="gotoApp(item)">
-        <img :src="item.icon" style="width: 100px; height: 100px"/>
-        <div>
-          {{ item.appName }}
+    <div id="app">
+      <div class="card" v-for="(item, index) in appList" :key="`dynamics-${index}`">
+        <div @click="gotoApp(item)">
+          <img class="card-left" :src="item.icon"/>
+          <div class="card-right">
+            <div class="app-title">
+              {{ item.appName }}
+            </div>
+            <div class="goto-app">
+              <div>进入系统</div>
+            </div>
+          </div>
         </div>
       </div>
     </div>
@@ -63,11 +70,11 @@
   if (type === 0) {
     await getAppMenuList(id, appCode)
   } else {
-    const data = await AppApi.getAppMenuList(id)
-    let userInfo = wsCache.get(CACHE_KEY.USER)
-    userInfo.menus = data
-    wsCache.set(CACHE_KEY.USER, userInfo)
-    wsCache.set(CACHE_KEY.ROLE_ROUTERS, data)
+    // const data = await AppApi.getAppMenuList(id)
+    // let userInfo = wsCache.get(CACHE_KEY.USER)
+    // userInfo.menus = data
+    // wsCache.set(CACHE_KEY.USER, userInfo)
+    // wsCache.set(CACHE_KEY.ROLE_ROUTERS, data)
     window.open(item.appDomain + '/index', '_blank')
     // window.open('/plat/shasteel', '_blank')
     // window.location.href = '/plat/shasteel'
@@ -78,24 +85,63 @@
 </script>
 
 <style lang="scss" scoped>
-#app {
-  width: 300px;
-  height: 200px;
-  display: inline-block;
-  background: transparent;
+#title {
+  width: 280px;
+  height: 51px;
+  margin: 30px auto;
+  font-family: Microsoft YaHei UI, Microsoft YaHei UI;
+  font-weight: bold;
+  font-size: 40px;
+  color: #282F3D;
 }
-
+#app {
+  margin: 0 96px;
+  width: 100%;
+}
 .card {
-  border: thin dashed gainsboro;
-  width: 150px;
-  height: 120px;
-  padding: 30px;
-  text-align: center;
-  justify-content: center;
-  font-size: 15px;
-  font-weight: bolder;
-  color: blue;
-  background: aliceblue;
-  border-radius: 10px;
+  width: 354px;
+  height: 200px;
+  margin: 0 24px 24px 0;
+  background: linear-gradient( 180deg, #E9F0FA 0%, #FFFFFF 100%);
+  border-radius: 12px 12px 12px 12px;
+  border: 2px solid;
+  border-image: linear-gradient(180deg, rgba(255, 255, 255, 1), rgba(255, 255, 255, 1)) 2 2;
+  display: inline-block;
+}
+.card > div{
+  display: inline-block;
+}
+.card-left{
+  height: 100px;
+  width: 100px;
+  float: left;
+  margin: 50px 30px;
+}
+.card-right {
+  float: right;
+  margin: 61px 10px;
+}
+.app-title {
+  width: 162px;
+  height: 32px;
+  font-family: Microsoft YaHei, Microsoft YaHei;
+  font-weight: bold;
+  font-size: 24px;
+  color: #282F3D;
+}
+.goto-app {
+  width: 96px;
+  height: 35px;
+  margin-top: 5px;
+  background: #3A99FD;
+  border-radius: 80px 80px 80px 80px;
+}
+.goto-app > div {
+  padding: 6px;
+  margin-left: 5px;
+  font-family: Microsoft YaHei UI, Microsoft YaHei UI;
+  font-weight: 400;
+  font-size: 18px;
+  color: #FFFFFF;
 }
 </style>
diff --git a/src/views/micro/index.vue b/src/views/micro/index.vue
index 1a4669c..92b9626 100644
--- a/src/views/micro/index.vue
+++ b/src/views/micro/index.vue
@@ -1,22 +1,20 @@
 <template>
   <div class="sub-app">
-    <WujieVue width="100%" height="100%" :name="name" :url="url" :alive="true" sync />
+    <WujieVue width="100%" height="100%" v-bind="computedOptions" :degrade="true" :alive="true" sync />
   </div>
 </template>
 <script lang="ts" setup>
-import hostMap from "@/utils/hostMap";
-import wujieVue from "wujie-vue3";
-const route = useRoute()
-const url = hostMap("//localhost:90/") + route.params.path
-const name = 'fast'
-watch(() => "$route.params.path",
-  () => {
-    wujieVue.bus.$emit("vue3-router-change", `/${route.params.path}`);
-  },
-  {
-    immediate: true
-  }
-)
+  import WujieVue from "wujie-vue3";
+  import { useRoute } from 'vue-router'
+  import { computed } from 'vue'
+
+  const route = useRoute()
+  const computedOptions = computed(() => {
+    return {
+      name: route.query.key,
+      url: route.query.url,
+    }
+  })
 </script>
 <style scoped lang="scss">
 .sub-app {
diff --git a/src/views/report/drag/index.vue b/src/views/report/drag/index.vue
new file mode 100644
index 0000000..295c10a
--- /dev/null
+++ b/src/views/report/drag/index.vue
@@ -0,0 +1,13 @@
+<template>
+  <ContentWrap>
+    <IFrame :src="src" />
+  </ContentWrap>
+</template>
+<script lang="ts" setup>
+import { getAccessToken } from '@/utils/auth'
+
+defineOptions({ name: 'Drag' })
+
+const BASE_URL = import.meta.env.VITE_BASE_URL
+const src = ref(BASE_URL + '/drag/list?token=' + getAccessToken())
+</script>
diff --git a/src/views/system/tenantPackage/TenantPackageForm.vue b/src/views/system/tenantPackage/TenantPackageForm.vue
index 7492889..c8bec1f 100644
--- a/src/views/system/tenantPackage/TenantPackageForm.vue
+++ b/src/views/system/tenantPackage/TenantPackageForm.vue
@@ -10,6 +10,12 @@
       <el-form-item label="套餐名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入套餐名" />
       </el-form-item>
+      <el-form-item label="套餐介绍" prop="description">
+        <el-input type="textarea" v-model="formData.description" placeholder="请输入套餐介绍" />
+      </el-form-item>
+      <el-form-item label="套餐图标">
+        <UploadImg v-model="formData.icon" :limit="1" />
+      </el-form-item>
       <el-form-item label="菜单权限">
         <el-card class="cardHeight">
           <template #header>
@@ -39,6 +45,18 @@
             show-checkbox
           />
         </el-card>
+      </el-form-item>
+      <el-form-item label="套餐标签" prop="labels">
+        <el-select
+          v-model="formData.labels"
+          filterable
+          multiple
+          allow-create
+          placeholder="请输入套餐标签"
+          style="width: 500px"
+        >
+          <el-option v-for="label in formData.labels" :key="label" :label="label" :value="label" />
+        </el-select>
       </el-form-item>
       <el-form-item label="状态" prop="status">
         <el-radio-group v-model="formData.status">
@@ -81,6 +99,9 @@
 const formData = ref({
   id: null,
   name: null,
+  icon: undefined,
+  labels: [],
+  description: null,
   remark: null,
   menuIds: [],
   status: CommonStatusEnum.ENABLE
diff --git a/src/views/system/tenantPackage/index.vue b/src/views/system/tenantPackage/index.vue
index fc68a4d..e135ec5 100644
--- a/src/views/system/tenantPackage/index.vue
+++ b/src/views/system/tenantPackage/index.vue
@@ -55,43 +55,51 @@
 
   <!-- 列表 -->
   <ContentWrap>
-    <el-table v-loading="loading" :data="list">
-      <el-table-column label="套餐编号" align="center" prop="id" width="120" />
-      <el-table-column label="套餐名" align="center" prop="name" />
-      <el-table-column label="状态" align="center" prop="status" width="100">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
-        </template>
-      </el-table-column>
-      <el-table-column label="备注" align="center" prop="remark" />
-      <el-table-column
-        label="创建时间"
-        align="center"
-        prop="createTime"
-        width="180"
-        :formatter="dateFormatter"
-      />
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            @click="openForm('update', scope.row.id)"
-            v-hasPermi="['system:tenant-package:update']"
+    <el-row :gutter="20">
+      <div v-loading="loading" class="package-card" v-for="(item, index) in packages" :key="`dynamics-${index}`">
+        <el-col :span="6">
+        <img class="card-icon" :src="item.icon" />
+        <div class="card-middle">
+          <div class="tenant-title">{{item.name}}</div>
+          <div class="tenant-operation">
+            <el-dropdown  @command="(command) => handleCommand(command, item)">
+              <el-button type="primary" link><Icon icon="ep:more-filled" /> </el-button>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item
+                    command="handleUpdate"
+                    v-if="checkPermi(['system:tenant-package:update'])"
+                  >
+                    <Icon icon="ep:edit" />修改
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+                <el-dropdown-menu>
+                  <el-dropdown-item
+                    command="handleDelete"
+                    v-if="checkPermi(['system:tenant-package:delete'])"
+                  >
+                    <Icon icon="ep:delete" />删除
+                  </el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </div>
+        <div class="description">{{item.description}}</div>
+        <div class="label-areas">
+          <el-tag
+            :disable-transitions="true"
+            :key="index"
+            v-for="(label, index) in item.labels"
+            :index="index"
+            class="label"
           >
-            修改
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['system:tenant-package:delete']"
-          >
-            删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
+            {{ label }}
+          </el-tag>
+        </div>
+      </el-col>
+      </div>
+    </el-row>
     <!-- 分页 -->
     <Pagination
       :total="total"
@@ -106,9 +114,10 @@
 </template>
 <script lang="ts" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { dateFormatter } from '@/utils/formatTime'
 import * as TenantPackageApi from '@/api/system/tenantPackage'
 import TenantPackageForm from './TenantPackageForm.vue'
+import {TenantPackageVO} from "@/api/system/tenantPackage";
+import {checkPermi} from "@/utils/permission";
 
 defineOptions({ name: 'SystemTenantPackage' })
 
@@ -117,7 +126,8 @@
 
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
-const list = ref([]) // 列表的数据
+const packages = ref([]) // 列表的数据
+
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -133,7 +143,7 @@
   loading.value = true
   try {
     const data = await TenantPackageApi.getTenantPackagePage(queryParams)
-    list.value = data.list
+    packages.value = data.list
     total.value = data.total
   } finally {
     loading.value = false
@@ -158,6 +168,20 @@
   formRef.value.open(type, id)
 }
 
+/** 操作分发 */
+const handleCommand = (command: string, row: TenantPackageVO) => {
+  switch (command) {
+    case 'handleUpdate':
+      openForm('update', row.id)
+      break
+    case 'handleDelete':
+      handleDelete(row.id)
+      break
+    default:
+      break
+  }
+}
+
 /** 删除按钮操作 */
 const handleDelete = async (id: number) => {
   try {
@@ -175,4 +199,68 @@
 onMounted(() => {
   getList()
 })
+
 </script>
+<style lang="scss" scoped>
+.package-card {
+  display: inline-block;
+  width: 396px;
+  height: 379px;
+  background: #FFFFFF;
+  border-radius: 4px 4px 4px 4px;
+  border: 1px solid #EBEDF0;
+  margin: 0px 8px 8px 0;
+}
+.card-icon {
+  width: 372px;
+  height: 200px;
+  margin: 10px 0 10px 2px;
+}
+.card-middle {
+  width: 396px;
+  height: 25px;
+  margin: 0 12px;
+  display: flex;
+}
+.tenant-title {
+  width: 340px;
+  height: 25px;
+  font-family: Microsoft YaHei UI, Microsoft YaHei UI;
+  font-weight: bold;
+  font-size: 20px;
+  color: #282F3D;
+}
+.tenant-operation {
+  margin-right: 12px;
+}
+.description {
+  margin: 8px 12px;
+  width: 372px;
+  height: 36px;
+  font-family: Microsoft YaHei, Microsoft YaHei;
+  font-weight: 400;
+  font-size: 14px;
+  color: #6B7785;
+  line-height: 18px;
+  word-wrap: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+}
+.label-areas {
+  display: flex;
+  flex-wrap: wrap;
+  height: 54px;
+  width: 396px;
+  margin: 0 8px;
+}
+.label {
+  width: 80px;
+  height: 20px;
+  margin: 4px;
+  border-radius: 80px 80px 80px 80px;
+  border: 1px solid #417CFF;
+}
+</style>

--
Gitblit v1.9.3