343 lines
8.7 KiB
Vue
343 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"
|
|
: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>
|