首页布局自适应
This commit is contained in:
parent
d16c0fdba3
commit
457dd6a09b
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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",
|
||||
|
|
3570
pnpm-lock.yaml
3570
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue