首页布局自适应

This commit is contained in:
z9130 2024-10-24 11:53:18 +08:00
parent d16c0fdba3
commit 457dd6a09b
8 changed files with 1634 additions and 5012 deletions

View File

@ -1,36 +1,37 @@
<script setup lang="ts">
// import { VueDraggable } from 'vue-draggable-plus'
import { computed } from 'vue';
interface IList {
name: string;
children: IList[];
}
interface Props {
modelValue: IList[];
}
const props = defineProps<Props>();
const emits = defineEmits<Emits>();
interface Emits {
(e: 'update:modelValue', value: IList[]): void;
}
const list = computed({
get: () => props.modelValue,
set: (value) => emits('update:modelValue', value),
});
</script>
<template>
<VueDraggable class="drag-area" tag="ul" v-model="list" group="g1">
<!-- <VueDraggable class="drag-area" tag="ul" v-model="list" group="g1">
<li v-for="el in modelValue" :key="el.name" class="grup-box">
<p>{{ el.name }}</p>
<nested-component v-model="el.children" />
</li>
</VueDraggable>
</VueDraggable> -->
</template>
<script setup lang="ts">
import { VueDraggable } from 'vue-draggable-plus'
import { computed } from 'vue'
interface IList {
name: string
children: IList[]
}
interface Props {
modelValue: IList[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:modelValue', value: IList[]): void
}
const emits = defineEmits<Emits>()
const list = computed({
get: () => props.modelValue,
set: value => emits('update:modelValue', value)
})
</script>
<style scoped>
.drag-area {
min-height: 50px;

View File

@ -1,25 +1,38 @@
<script setup>
import { defineAsyncComponent, getCurrentInstance, markRaw, onMounted, ref,nextTick } from 'vue';
import {
defineAsyncComponent,
getCurrentInstance,
markRaw,
nextTick,
onMounted,
ref,
toRefs,
} from 'vue';
import { UndoOutlined, CheckOutlined, CloseCircleFilled, QuestionCircleOutlined, SyncOutlined, ShoppingCartOutlined, EditOutlined } from '@ant-design/icons-vue';
import { CheckboxGroup, Checkbox, Collapse, CollapsePanel, FloatButtonGroup, FloatButton, BackTop, Popover } from 'ant-design-vue';
import { CloseCircleFilled } from '@ant-design/icons-vue';
import { storeToRefs } from 'pinia';
import { toRefs } from 'vue'
import { UseTilesStore } from '#/store';
import { storeToRefs } from 'pinia'
const tilesStore = UseTilesStore();
import {
debounce,
generateRandomString,
updateRowHeightByGroup,
} from '../../utils';
const props = defineProps({
list: {
type: Object,
default: []
default: [],
},
})
let { list } = toRefs(props);
});
const tilesStore = UseTilesStore();
const { list } = toRefs(props);
const { proxy } = getCurrentInstance();
const layout = ref(list.value)
const layout = ref(list.value);
onMounted(() => {
// layout.value = [
// {
@ -57,7 +70,7 @@ onMounted(() => {
// },
// },
// ]
})
});
const colNum = 12;
let defaultH = 2;
let defaultW = 2;
@ -73,7 +86,23 @@ const DragPos = {
i: null,
};
let currentDragCom = null;
/** 行高 */
const rowHeight = ref(0);
/** 屏幕宽度 */
const screenW = ref(0);
const domId = `child-${generateRandomString(8)}`;
// updateRowHeight 200ms
const debouncedUpdateRowHeight = debounce(() => {
rowHeight.value = updateRowHeightByGroup(`#${domId}`);
}, 0);
onMounted(() => {
window.addEventListener('resize', debouncedUpdateRowHeight);
rowHeight.value = updateRowHeightByGroup(`#${domId}`); //
document.addEventListener(
'dragover',
(e) => {
@ -228,12 +257,11 @@ const dragend = (e) => {
try {
proxy.$refs.gridItem[layout.value.length].$refs.item.style.display =
'block';
} catch {
}
} catch {}
}
nextTick(() => {
tilesIsMove.value = true;
})
});
};
// resize使resize
const resizedEvent = (e) => {
@ -251,30 +279,30 @@ const delItem = (item) => {
};
//
let shop = ref(false)
const shop = ref(false);
//
let editTiles = ref(false)
const editTiles = ref(false);
//
let activeKeyArr = ref(['1', '2', '3'])
const activeKeyArr = ref(['1', '2', '3']);
//
let selectTilseArr = ref([])
const selectTilseArr = ref([]);
//
let addTiles = (val) => {
let arr = JSON.parse(JSON.stringify(selectTilseArr.value))
const addTiles = (val) => {
let arr = JSON.parse(JSON.stringify(selectTilseArr.value));
if (arr.includes(val)) {
arr = arr.filter((item) => {
return item != val
})
return item != val;
});
} else {
arr.push(val)
arr.push(val);
}
selectTilseArr.value = arr
}
selectTilseArr.value = arr;
};
//
let {tilesIsMove} = storeToRefs(tilesStore)
let { tilesIsMove } = storeToRefs(tilesStore);
//
let cancelOrSure = (type) => {
const cancelOrSure = (type) => {
if (type == 'cance') {
editTiles.value = false;
tilesIsMove.value = false;
@ -282,30 +310,60 @@ let cancelOrSure = (type) => {
editTiles.value = true;
tilesIsMove.value = true;
}
}
};
//
let goPage = (item) => {
const goPage = (item) => {
if (tilesIsMove) return;
router.push(item?.path);
}
};
</script>
<template>
<div class="container-group">
<div :id="domId" class="container-group">
<!-- 自定义布局的部分 -->
{{ rowHeight }}
<div class="grid-box select-none">
<grid-layout ref="gridLayout" v-model:layout="layout" :col-num="4" :is-draggable="tilesIsMove" :is-mirrored="false"
:auto-size="false" :is-resizable="false" :margin="[10, 10]" :row-height="40"
:vertical-compact="true">
<grid-item v-for="(item, index ) in layout" :key="item.i" ref="gridItem" :h="item.h" :i="item.i" :w="item.w"
:x="item.x" :y="item.y" :dragAllowFrom="item.component&&item.component.dom?item.component.dom:null" @resized="resizedEvent">
<span class="close" @click="delItem(item)" v-if="tilesIsMove">
<CloseCircleFilled style="color: #f10215;" />
<grid-layout
v-if="rowHeight !== 0"
ref="gridLayout"
v-model:layout="layout"
:auto-size="true"
:col-num="4"
:is-draggable="tilesIsMove"
:is-mirrored="false"
:is-resizable="false"
:margin="[10, 10]"
:row-height="rowHeight"
:vertical-compact="true"
>
<grid-item
v-for="(item, index) in layout"
:key="item.i"
ref="gridItem"
:drag-allow-from="
item.component && item.component.dom ? item.component.dom : null
"
:h="item.h"
:i="item.i"
:w="item.w"
:x="item.x"
:y="item.y"
@resized="resizedEvent"
>
<span v-if="tilesIsMove" class="close" @click="delItem(item)">
<CloseCircleFilled style="color: #f10215" />
</span>
<div class="py-2 px-4 box-border w-[100%] h-[100%] us-card-box bg-background" @click="goPage(item)">
<component :is="loadComponent(item.component)" :data="item" :key="item.i" :type="'sm'"/>
<div
class="us-card-box bg-background box-border h-[100%] w-[100%] min-w-[50px] px-2 py-2"
@click="goPage(item)"
>
<component
:is="loadComponent(item.component)"
:key="item.i"
:data="item"
type="sm"
/>
</div>
</grid-item>
</grid-layout>
@ -324,7 +382,6 @@ let goPage = (item) => {
height: 100%;
}
.components-box {
padding: 12px 20px;
// border: 1px solid rgb(66 66 66 / 100%);
@ -363,11 +420,10 @@ let goPage = (item) => {
margin-bottom: 8px;
}
img {
width: 100%;
// height: 100%;
object-fit: contain
object-fit: contain;
}
}
}

View File

@ -4,6 +4,7 @@ import {
getCurrentInstance,
markRaw,
nextTick,
onBeforeUnmount,
onMounted,
ref,
} from 'vue';
@ -30,6 +31,7 @@ import { storeToRefs } from 'pinia';
import { UseTilesStore } from '#/store';
import { tilesList } from './tiles';
import { debounce, updateRowHeight } from './utils';
const tilesStore = UseTilesStore();
@ -67,7 +69,21 @@ const DragPos = {
};
const componentsInfo = tilesList;
let currentDragCom = null;
/** 行高 */
const rowHeight = ref(0);
/** 屏幕宽度 */
const screenW = ref(0);
// updateRowHeight 200ms
const debouncedUpdateRowHeight = debounce(() => {
rowHeight.value = updateRowHeight('#container-canvas');
}, 0);
onMounted(() => {
window.addEventListener('resize', debouncedUpdateRowHeight);
rowHeight.value = updateRowHeight('#container-canvas'); //
document.addEventListener(
'dragover',
(e) => {
@ -83,6 +99,12 @@ onMounted(() => {
});
processLayout(layout.value);
});
//
onBeforeUnmount(() => {
window.removeEventListener('resize', debouncedUpdateRowHeight);
});
//
const loadComponent = (path) => {
return defineAsyncComponent(markRaw(() => import(`${path}`)));
@ -292,20 +314,22 @@ const goPage = (item) => {
</script>
<template>
<div class="container h-[calc(100%-10px)] px-[20px]">
<div id="container-canvas" class="container h-[calc(100%-10px)] px-[20px]">
<!-- 自定义布局的部分 -->
{{ screenW }} - {{ rowHeight }}
<div class="grid-box index-grid select-none">
<grid-layout
v-if="rowHeight != 0"
ref="gridLayout"
v-model:layout="layout"
:auto-size="false"
:auto-size="true"
:col-num="12"
:is-draggable="tilesIsMove"
:is-mirrored="false"
:is-resizable="tilesIsMove"
:margin="[10, 10]"
:responsive="false"
:row-height="70"
:row-height="rowHeight"
:vertical-compact="true"
>
<grid-item

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
// 防抖函数
export function debounce(func: Function, wait: number) {
let timeout: NodeJS.Timeout;
return function (...args: any[]) {
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
/**
*
*/
export const updateRowHeight = (domId: string) => {
// const screenWidth = (screenW.value = window.innerWidth);
let rowHeight = 0;
// 获取 id 为 'container-canvas' 的元素宽度
const container = document.querySelector(domId);
if (!container) {
return; // 如果没有找到容器,直接返回
}
const containerWidth = container.offsetWidth; // 获取容器宽度
// const containerWidth = container.offsetWidth; // 获取容器宽度
// screenW.value = containerWidth;
if (containerWidth > 2560) {
rowHeight = 85; // 超大屏 (如 4K 屏幕)
} else if (containerWidth > 2400) {
rowHeight = 80; // 接近 4K 的高分辨率屏幕
} else if (containerWidth > 1920) {
rowHeight = 70; // 大屏 (如 1080p 屏幕)
} else if (containerWidth > 1680) {
rowHeight = 65; // 中大屏幕 (1680px ~ 1920px)
} else if (containerWidth > 1440) {
rowHeight = 60; // 中大屏幕 (1440px ~ 1680px)
} else if (containerWidth > 1366) {
rowHeight = 60; // 中等屏幕 (1366px ~ 1440px)
} else if (containerWidth > 1280) {
rowHeight = 55; // 中等屏幕 (1280px ~ 1366px)
} else if (containerWidth > 1152) {
rowHeight = 50; // 较小的中屏 (1152px ~ 1280px)
} else if (containerWidth > 1024) {
rowHeight = 45; // 小屏 (1024px ~ 1152px)
} else {
rowHeight = 40; // 超小屏幕 (小于 1024px)
}
console.log(`屏幕 ${domId}resize 监测:`, containerWidth, rowHeight);
return rowHeight;
};
/**
*
*/
export const updateRowHeightByGroup = (domId: string) => {
// const screenWidth = (screenW.value = window.innerWidth);
let rowHeight = 0;
// 获取 id 为 'container-canvas' 的元素宽度
const container = document.querySelector(domId);
if (!container) {
return; // 如果没有找到容器,直接返回
}
const containerWidth = container.offsetWidth; // 获取容器宽度
// const containerWidth = container.offsetWidth; // 获取容器宽度
// screenW.value = containerWidth;
if (containerWidth > 1500) {
rowHeight = 100; // 超大屏 (大于1500px)
} else if (containerWidth > 1400) {
rowHeight = 95; // 宽度 1400px ~ 1500px
} else if (containerWidth > 1300) {
rowHeight = 90; // 宽度 1300px ~ 1400px
} else if (containerWidth > 1200) {
rowHeight = 85; // 宽度 1200px ~ 1300px
} else if (containerWidth > 1100) {
rowHeight = 80; // 宽度 1100px ~ 1200px
} else if (containerWidth > 1000) {
rowHeight = 75; // 宽度 1000px ~ 1100px
} else if (containerWidth > 900) {
rowHeight = 70; // 宽度 900px ~ 1000px
} else if (containerWidth > 800) {
rowHeight = 65; // 宽度 800px ~ 900px
} else if (containerWidth > 700) {
rowHeight = 60; // 宽度 700px ~ 800px
} else if (containerWidth > 600) {
rowHeight = 55; // 宽度 600px ~ 700px
} else if (containerWidth > 500) {
rowHeight = 50; // 宽度 500px ~ 600px
} else if (containerWidth > 400) {
rowHeight = 45; // 宽度 400px ~ 500px
} else if (containerWidth > 300) {
rowHeight = 40; // 宽度 300px ~ 400px
} else if (containerWidth > 200) {
rowHeight = 35; // 宽度 200px ~ 300px
} else {
rowHeight = 30; // 宽度 150px ~ 200px (最小屏幕)
}
console.log(`屏幕 ${domId}resize 监测:`, containerWidth, rowHeight);
return rowHeight;
};
/**
* 12
* @returns {string} 12
*/
export function generateRandomString(len: number = 12): string {
const characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < len; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}

View File

@ -43,11 +43,7 @@
"clean": "vsh clean",
"commit": "czg",
"dev": "turbo-run dev",
"dev:office": "pnpm -F web-office run dev",
"dev:contract": "pnpm -F web-contract run dev",
"dev:facilities": "pnpm -F web-facilities run dev",
"dev:materials": "pnpm -F web-materials run dev",
"dev:oa": "pnpm -F web-oa run dev",
"dev:test": "pnpm -F web-test run dev",
"dev:antd": "pnpm -F @vben/web-antd run dev",
"dev:docs": "pnpm -F @vben/docs run dev",
"dev:ele": "pnpm -F @vben/web-ele run dev",

File diff suppressed because it is too large Load Diff

View File

@ -8,18 +8,6 @@
"name": "@vben/web-antd",
"path": "apps/web-antd",
},
{
"name": "web-contract",
"path": "apps/web-contract",
},
{
"name": "web-facilities",
"path": "apps/web-facilities",
},
{
"name": "web-office",
"path": "apps/web-office",
},
{
"name": "web-test",
"path": "apps/web-test",