342 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="page-view-wrapp">
 | |
|     <div v-if="!isInQiankun" class="project">
 | |
|       <span>项目: </span>
 | |
|       <a-select
 | |
|         style="min-width: 160px"
 | |
|         placeholder="请选择项目"
 | |
|         v-model:value="projectVal"
 | |
|         :options="projectOptions"
 | |
|         @change="handleProjectChange"
 | |
|       ></a-select>
 | |
|     </div>
 | |
|     <div>
 | |
|       <grid-layout
 | |
|         v-if="isDraggable"
 | |
|         :layout.sync="layoutList"
 | |
|         :col-num="2"
 | |
|         :is-draggable="true"
 | |
|         :is-resizable="false"
 | |
|         :is-mirrored="false"
 | |
|         :vertical-compact="true"
 | |
|         :use-css-transforms="true"
 | |
|       >
 | |
|         <grid-item
 | |
|           v-for="(item, index) in layoutList"
 | |
|           :x="item.x"
 | |
|           :y="item.y"
 | |
|           :w="item.w"
 | |
|           :h="item.h"
 | |
|           :i="item.i"
 | |
|           :key="item.i"
 | |
|           drag-allow-from=".vue-draggable-handle"
 | |
|           drag-ignore-from=".no-drag"
 | |
|         >
 | |
|           <div class="view-box view-draggable">
 | |
|             <div class="vue-draggable-handle"><BarsOutlined /></div>
 | |
|             <div class="content no-drag">
 | |
|               <a-spin :spinning="ids[index].loading">
 | |
|                 <div class="card-content">
 | |
|                   <y-table
 | |
|                     v-if="item.data.type === VIEW_TYPE.TABLE"
 | |
|                     :preview-id="item.id"
 | |
|                     :filter-config="item.data.filter"
 | |
|                     :data-list="item.data.data"
 | |
|                     :column-config="item.data.header"
 | |
|                     :total="item.data.count"
 | |
|                     :title="item.data.preview_name"
 | |
|                     :is-export="item.data.is_export"
 | |
|                     @toFilt="
 | |
|                       (params?:object) => {
 | |
|                         handleSingle(ids[index], params);
 | |
|                       }
 | |
|                     "
 | |
|                   ></y-table>
 | |
|                   <y-chart
 | |
|                     v-if="item.data.type === VIEW_TYPE.CHART"
 | |
|                     :chartCfg="item.data.config"
 | |
|                     :title="item.data.preview_name"
 | |
|                     :filter-config="item.data.filter"
 | |
|                     @toFilt="
 | |
|                     (params?:object) => {
 | |
|                       handleSingle(ids[index], params);
 | |
|                       }
 | |
|                     "
 | |
|                   ></y-chart>
 | |
|                 </div>
 | |
|               </a-spin>
 | |
|             </div>
 | |
|           </div>
 | |
|         </grid-item>
 | |
|       </grid-layout>
 | |
| 
 | |
|       <a-row v-else :gutter="[16, 16]">
 | |
|         <a-col v-for="(item, index) in layoutList" :span="24">
 | |
|           <a-spin :spinning="item.loading">
 | |
|             <div>
 | |
|               <div class="view-box">
 | |
|                 <div class="content">
 | |
|                   <div class="card-content">
 | |
|                     <y-table
 | |
|                       v-if="item.data.type === VIEW_TYPE.TABLE"
 | |
|                       :preview-id="item.id"
 | |
|                       :filter-config="item.data.filter"
 | |
|                       :data-list="item.data.data"
 | |
|                       :column-config="item.data.header"
 | |
|                       :total="item.data.count"
 | |
|                       :title="item.data.preview_name"
 | |
|                       :is-export="item.data.is_export"
 | |
|                       @toFilt="
 | |
|                         (params?:object) => {
 | |
|                           handleSingle(ids[index], params,);
 | |
|                         }
 | |
|                       "
 | |
|                     ></y-table>
 | |
|                     <y-chart
 | |
|                       v-if="item.data.type === VIEW_TYPE.CHART"
 | |
|                       :chartCfg="item.data.config"
 | |
|                       :title="item.data.preview_name"
 | |
|                       :filter-config="item.data.filter"
 | |
|                       @toFilt="
 | |
|                         (params?:object) => {
 | |
|                           handleSingle(ids[index], params);
 | |
|                         }
 | |
|                       "
 | |
|                     ></y-chart>
 | |
|                   </div>
 | |
|                 </div>
 | |
|               </div>
 | |
|             </div>
 | |
|           </a-spin>
 | |
|         </a-col>
 | |
|       </a-row>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| <script setup lang="ts">
 | |
| import { ref, shallowRef, computed, onMounted, watch } from "vue";
 | |
| import { useRoute, useRouter } from "vue-router";
 | |
| import { BarsOutlined } from "@ant-design/icons-vue";
 | |
| // utils
 | |
| import PLimit from "p-limit";
 | |
| // api
 | |
| import { searchInfo } from "@/api/preview/index";
 | |
| import { getProjectDrop } from "@/api/common";
 | |
| import { getPageInfo } from "./service";
 | |
| import type { SelectProps } from "ant-design-vue";
 | |
| import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
 | |
| 
 | |
| interface ItemDetail {
 | |
|   id: number | string;
 | |
|   data: any;
 | |
|   loading: boolean;
 | |
| }
 | |
| 
 | |
| interface Item {
 | |
|   id: number | string;
 | |
|   data: any;
 | |
|   loading: boolean;
 | |
| }
 | |
| 
 | |
| interface Option extends SelectProps {
 | |
|   mark: string;
 | |
| }
 | |
| 
 | |
| const VIEW_TYPE = {
 | |
|   TABLE: "table",
 | |
|   CHART: "chart",
 | |
| };
 | |
| 
 | |
| const SEARCH_TYPE = {
 | |
|   SEARCH: "search",
 | |
|   INIT: "init",
 | |
| };
 | |
| 
 | |
| // hooks
 | |
| const route = useRoute();
 | |
| const router = useRouter();
 | |
| const projectTag = shallowRef();
 | |
| const projectVal = shallowRef();
 | |
| const pageId = shallowRef(route.query.pageId);
 | |
| const projectOptions = shallowRef<Option[]>();
 | |
| const isDraggable = false;
 | |
| 
 | |
| const isInQiankun = computed(() => {
 | |
|   return qiankunWindow.__POWERED_BY_QIANKUN__ || window.proxy?.__POWERED_BY_QIANKUN__
 | |
| })
 | |
| 
 | |
| const layoutList = computed(() => {
 | |
|   return ids.value.map((item, index) => {
 | |
|     // 当前是第几行
 | |
|     const row = Math.floor(index / 2);
 | |
|     // 当前是第几列ji
 | |
|     const col = index % 2;
 | |
|     return {
 | |
|       i: item?.id,
 | |
|       x: col,
 | |
|       y: row,
 | |
|       w: 1,
 | |
|       h: 3,
 | |
|       minH: 3,
 | |
|       ...item,
 | |
|     };
 | |
|   });
 | |
| });
 | |
| const ids = ref<Item[]>([]);
 | |
| 
 | |
| const pLimit = PLimit(2);
 | |
| 
 | |
| watch(() => route.query.viewId, () => {
 | |
|   getPageInfoData()
 | |
| })
 | |
| 
 | |
| onMounted(() => {
 | |
|   getProjectList();
 | |
| });
 | |
| 
 | |
| const handleSingle = (info: ItemDetail, otherParams?: object) => {
 | |
|   getSinglePreview({ info, otherParams, type: SEARCH_TYPE.SEARCH });
 | |
| };
 | |
| 
 | |
| const handleProjectChange = (value: string | number, option: Option) => {
 | |
|   projectTag.value = option.mark;
 | |
|   router.replace({
 | |
|     path: route.path,
 | |
|     query: {
 | |
|       ...route.query,
 | |
|       projectTag: projectTag.value,
 | |
|     },
 | |
|   });
 | |
|   getPageInfoData();
 | |
| };
 | |
| 
 | |
| // 请求
 | |
| 
 | |
| // 获取项目下拉
 | |
| const getProjectList = () => {
 | |
|   getProjectDrop()
 | |
|     .then((res) => {
 | |
|       if (res.code === 200) {
 | |
|         projectOptions.value = res.data;
 | |
|         projectTag.value = route.query.projectTag || res.data[0].mark;
 | |
|         projectVal.value =
 | |
|           projectOptions.value?.find((item) => {
 | |
|             return item.mark === route.query.projectTag;
 | |
|           })?.value || res.data[0].value;
 | |
|         getPageInfoData();
 | |
|       }
 | |
|     })
 | |
|     .catch(() => {
 | |
|       projectOptions.value = [];
 | |
|     })
 | |
|     .finally(() => {});
 | |
| };
 | |
| 
 | |
| // 单个视图请求
 | |
| const getSinglePreview = (data: {
 | |
|   info: ItemDetail;
 | |
|   otherParams?: object;
 | |
|   type?: string;
 | |
| }) => {
 | |
|   const { info, otherParams, type } = data;
 | |
|   info.loading = true;
 | |
|   const params = { previewId: info.id, page: 1, perPage: 20, ...otherParams };
 | |
|   searchInfo(params)
 | |
|     .then((res) => {
 | |
|       if (res.code === 200) {
 | |
|         info.data = res.data;
 | |
|       }
 | |
|     })
 | |
|     .finally(() => {
 | |
|       info.loading = false;
 | |
|     });
 | |
| };
 | |
| 
 | |
| // 获取页面信息所有的id
 | |
| const getPageInfoData = () => {
 | |
|   getPageInfo({ mark:projectTag.value, page_id: pageId.value ?? "-1" })
 | |
|     .then((res) => {
 | |
|       if (res.code === 200) {
 | |
|         if (route.query.viewId) {
 | |
|           ids.value = res.data?.filter((item: any) => {
 | |
|             return item.preview_id === Number(route.query.viewId);
 | |
|           }).map((item: any) => {
 | |
|             return {
 | |
|               id: item.preview_id,
 | |
|               data: item,
 | |
|               loading: false,
 | |
|             }
 | |
|           })
 | |
|         } else {
 | |
|           ids.value = res.data?.map((item: any) => {
 | |
|             return {
 | |
|               id: item.preview_id,
 | |
|               data: item,
 | |
|               loading: false,
 | |
|             };
 | |
|           });
 | |
|         }
 | |
|        
 | |
|         getAllCardsData();
 | |
|       }
 | |
|     })
 | |
|     .finally(() => {});
 | |
| };
 | |
| 
 | |
| const fetchFn = (delay: number, info: ItemDetail) => {
 | |
|   return new Promise((resolve) => {
 | |
|     setTimeout(() => {
 | |
|       resolve(info);
 | |
|       getSinglePreview({ info, type: SEARCH_TYPE.INIT });
 | |
|     }, delay);
 | |
|   });
 | |
| };
 | |
| 
 | |
| const getAllCardsData = async () => {
 | |
|   let listDB = [];
 | |
|   for (let i in ids.value) {
 | |
|     listDB.push(pLimit(() => fetchFn(i === "0" ? 200 : 1000, ids.value[i])));
 | |
|   }
 | |
|   await Promise.all(listDB);
 | |
|   //此处的listDB就是最后整合的数据
 | |
| };
 | |
| </script>
 | |
| <style lang="less" scoped>
 | |
| .view-box {
 | |
|   height: 100%;
 | |
|   width: 100%;
 | |
|   min-height: 350px;
 | |
|   background-color: #fff;
 | |
|   border: 1px solid #fff;
 | |
|   border-radius: 4px;
 | |
|   transition: all 0.3s;
 | |
|   &:hover {
 | |
|     box-shadow: 0 0 20px 0 #0a103205, 0 14px 40px 0 #0a103208,
 | |
|       0 20px 60px 0 #0a10320d;
 | |
|   }
 | |
| 
 | |
|   .content {
 | |
|     padding: 10px;
 | |
|   }
 | |
| }
 | |
| 
 | |
| .project {
 | |
|   margin-bottom: 10px;
 | |
| }
 | |
| 
 | |
| .view-draggable {
 | |
|   height: auto;
 | |
|   min-height: 450px;
 | |
| }
 | |
| 
 | |
| .vue-draggable-handle {
 | |
|   padding: 0 8px 8px 0;
 | |
|   border-radius: 10px;
 | |
|   cursor: pointer;
 | |
| }
 | |
| 
 | |
| .vue-grid-item {
 | |
|   height: auto;
 | |
| }
 | |
| </style>
 | 
