2024-07-30 20:04:38 +08:00

340 lines
8.7 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"
: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"
: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>