目录
1.说明
前端使用grid布局,生成一个X乘Y的矩阵。
2.grid布局的常用属性的说明及使用
html部分
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>4x5 Grid Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
<div class="grid-item">10</div>
<div class="grid-item">11</div>
<div class="grid-item">12</div>
<div class="grid-item">13</div>
<div class="grid-item">14</div>
<div class="grid-item">15</div>
<div class="grid-item">16</div>
</div>
</body>
</html>
css部分
body {
font-family: Arial, sans-serif;
}
.grid-container {
display: grid;
grid-template-columns: repeat(5, 1fr); /* 5 列 */
grid-template-rows: repeat(4, 100px); /* 4 行,每行高度为 100px */
gap: 10px; /* 网格项之间的间距 */
padding: 10px;
}
.grid-item {
background-color: #4CAF50; /* 背景颜色 */
color: white; /* 字体颜色 */
display: flex; /* 使用 flexbox 居中内容 */
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
border: 1px solid #fff; /* 边框 */
}
说明:
首先设置外面大div的css:
① 设置布局模式为grid布局
display: grid;
②设置每行展示的列数及列宽
grid-template-columns: repeat(5, 1fr); /* 5 列,每列占据相等的宽度 */
grid-template-columns: 100px 200px 150px; /* 三列,分别为 100px, 200px, 150px */
grid-template-columns: 50% 30% 20%; /* 三列,分别占据容器宽度的 50%, 30%, 20% */
grid-template-columns: auto auto; /* 两列,宽度根据内容自动变化 */
grid-template-columns: 1fr 2fr; /* 第一列占据 1 份,第二列占据 2 份,比例为 1:2 */
grid-template-columns: 100px 1fr 2fr; /* 第一列固定 100px,第二列与第三列按比例分配剩余空间 */
grid-template-columns: repeat(3, 100px); /* 创建 3 列,每列宽度为 100px */
grid-template-columns: 100px repeat(2, 1fr); /* 第一列 100px,后面两列平分剩余空间 */
grid-template-columns: 100px 200px 1fr; /* 第一列 100px,第二列 200px,第三列自适应剩余空间 */
grid-template-columns: repeat(2, 150px) 1fr; /* 前两列固定为 150px,最后一列自适应剩余空间 */
上面几种设置列数及列宽的方法中,如果设置列宽自适应时,当大div的宽度较大,每行的小div较少时,会导致div之间的间距较大。可以采用下面的方式将列宽固定
grid-template-columns: repeat(3, minmax(100px, 100px));
grid-template-columns: repeat(3, 100px);
上面的设置方式代表,显示3列,每列的宽度固定为100px。
额外说明一下repeat
repeat(count, size)
- count: 指定重复的次数,可以是一个整数(如
3
),也可以是一个关键字(如auto-fill
或auto-fit
)。 - size: 定义每次重复的大小,可以是固定的长度单位(例如
px
、em
、rem
)、灵活的单位(例如fr
),或者使用其他函数(如minmax()
)来定义最小和最大值。
③设置显示的行数及行高,和列的设置一致
grid-template-rows: repeat(4, 100px); /* 4 行,每行高度为 100px */
④设置列间距及行间距
gap: 10px; /* 列之间的间距及行之间的间距 */
row-gap: 20px; /* 设置行间距为 20px */
column-gap: 15px; /* 设置列间距为 15px */
3.使用示例
<template>
<a-modal :visible="drawerVisible" width="50%"
unmountOnClose :mask-closable="false" :closable="false" :esc-to-close="false" :draggable="true">
<template #title>
<span> {{ type === "1" ? "Add Experiment Layout Template" : "Edit Experiment Layout Template" }} </span>
</template>
<template #footer>
<a-button type="primary" @click="handleCancel">Cancel</a-button>
<a-button type="primary" @click="handleNext">Next</a-button>
<a-button type="primary" @click="handleOk" :loading="okLoading">Finish</a-button>
</template>
<a-form ref="formRef" :model="insertForm" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
label-align="left" :rules="rules">
<a-row :gutter="20">
<a-col :span="20">
<a-form-item field="templateName" label="模板名称">
<a-input v-model.trim="insertForm.templateName" placeholder="请填写模板名称" :max-length="80" allow-clear
show-word-limit/>
</a-form-item>
<a-form-item field="numEntries" label="数量">
<a-input-number v-model="insertForm.numEntries" placeholder="请填写数量" allow-clear :min="1" :step="1"
:max-length="4" show-word-limit
:precision="0"/>
</a-form-item>
<a-form-item field="plotsWide" label="地块长度">
<a-input-number v-model="insertForm.plotsWide" placeholder="请填写地块长度" allow-clear :min="1"
:max="insertForm.numEntries ? insertForm.numEntries : 999" :step="1" :max-length="3"
:precision="0" show-word-limit/>
</a-form-item>
<a-form-item field="sizeRestriction" label="大小限制">
<a-select v-model="insertForm.sizeRestriction" placeholder="请填写大小限制" :options="sizeRestrict" allow-clear
allow-search/>
</a-form-item>
<a-form-item field="mapPlacement" label="种植顺序">
<a-select v-model="insertForm.mapPlacement" placeholder="请填写种植顺序" :options="mapPlacement" allow-clear
allow-search/>
</a-form-item>
<a-form-item field="enabled" label="是否可用">
<a-switch v-model="insertForm.enabled" :checked-value="1" :unchecked-value="0"/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
<a-modal :visible="templateVisible" width="80%"
:mask-closable="false" :closable="false" :esc-to-close="false" :draggable="true">
<template #title>
<span> {{ type === "1" ? "Add Experiment Layout Template" : "Edit Experiment Layout Template" }} </span>
</template>
<template #footer>
<a-button type="primary" @click="handleCancelMap">Cancel</a-button>
<a-button type="primary" @click="handlePrev">Prev</a-button>
<a-button type="primary" @click="handleOk" :loading="okLoading">Finish</a-button>
</template>
<div style="display: flex;">
<a-spin :loading="mapLoading" style="width: 85%">
<div class="container" id="parentDiv" ref="divRef" :style="setGridTemplateColumns()">
<div class="input-wrapper" v-for="(item,index) in map" :id="'div' + index">
<!-- <span>{{ item.entryNum }}</span>-->
<a-input :id="'input' + index" class="input" :style="setDefaultColor(item.regionNum)"
v-model="item.checkNum" :disabled="item.disable === '1'" :max-length="5"
@focus="inputClick(index)" @change="changeVal(index)"/>
</div>
</div>
</a-spin>
<div style="margin-left: 10px">
<a-table :data="data" :pagination="false" row-key="region" :row-selection="rowSelection"
v-model:selectedKeys="selectedKeys">
<template #columns>
<a-table-column title="Region" data-index="region"></a-table-column>
<a-table-column title="Count">
<template #cell="{ record }">
<div :style="`background-color:${record.color}`">{{ record.count }}</div>
</template>
</a-table-column>
</template>
</a-table>
<div style="margin-top: 15px">
<a-button @click="setColor">Assign Region</a-button>
</div>
</div>
</div>
<div style="margin-top: 10px">
<span>Total Entries: {{ insertForm.numEntries }} </span>
<span>#Checks: {{ checksNum }} ({{ checkRatio }}%) </span>
<span>Non-Checks: {{ noChecksNum }}</span>
</div>
<div style="margin-top: 10px">
<a-space :size="5">
<a-button type="primary" @click="handlePattern">Pattern</a-button>
<a-button type="primary" @click="handleClearChecks">Clear All Checks</a-button>
<a-button type="primary" @click="handleClearRegions">Clear All Regions</a-button>
</a-space>
</div>
</a-modal>
<a-modal :visible="patternVisible" width="40%" @ok="patternOk" @cancel="patternCancel"
:mask-closable="false" :closable="false" :esc-to-close="false" :draggable="true">
<template #title>
<span> Check Pattern </span>
</template>
<a-form ref="patternFormRef" :model="patternData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
label-align="left" :rules="patternRules">
<a-row :gutter="20">
<a-col :span="20">
<a-form-item field="xVal" label="X Increment">
<a-input-number v-model.trim="patternData.xVal" :min="1" :step="1" :max="insertForm.plotsWide - 1"
:precision="0" allow-clear/>
</a-form-item>
<a-form-item field="yVal" label="Y Increment">
<a-input-number v-model="patternData.yVal" :min="1" :step="1" :max="rows-2" :precision="0" allow-clear/>
</a-form-item>
<a-form-item field="checkOption" label="check Options">
<a-radio-group v-model="patternData.checkOption" direction="vertical" :options="checkNumberOption">
</a-radio-group>
</a-form-item>
<a-form-item field="setVal" label="Set val" v-if="patternData.checkOption === 1 ">
<a-input-number v-model.trim="patternData.setVal" :min="1" :step="1" :max="99999" :precision="0"
allow-clear/>
</a-form-item>
<a-form-item field="minVal" label="Minimum" v-if="patternData.checkOption === 2 ">
<a-input-number v-model.trim="patternData.minVal" :min="1" :step="1" :max="99999" :precision="0"
allow-clear/>
</a-form-item>
<a-form-item field="maxVal" label="Maximum" v-if="patternData.checkOption === 2 ">
<a-input-number v-model.trim="patternData.maxVal" :min="patternData.minVal" :step="1" :max="99999"
:precision="0" allow-clear/>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
</template>
<script lang="ts" setup>
import {addEdit, getEditData, getMapInfo} from '@/api/dictionaries/expLayoutTemplate'
import {reactive, ref, computed} from "vue";
import {FormInstance} from '@arco-design/web-vue/es/form';
import {Message} from '@arco-design/web-vue';
const formRef = ref<FormInstance>();
const patternFormRef = ref()
// 父组件传递的参数(所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递)
const props = defineProps({
type: String,
});
const emits = defineEmits(['handleQuery']);
// 确认按钮的加载状态
const okLoading = ref(false);
const drawerVisible = ref(false);
const templateVisible = ref(false)
const mapLoading = ref(false)
const patternVisible = ref(false)
const insertFormData = () => {
return {
layoutTemplateId: "",
templateName: "",
numEntries: undefined,
plotsWide: undefined,
mapPlacement: 2,
sizeRestriction: 1,
enabled: 1,
};
};
const checkNumberOption = [
{label: 'Set all to val', value: 1},
{label: 'Randomize Check Numbers', value: 2},
];
const patternFormData = () => {
return {
xVal: 1,
yVal: 1,
checkOption: 1,
setVal: 1,
minVal: 1,
maxVal: 1,
};
}
const insertForm = ref(insertFormData());
const patternData = ref(patternFormData())
const mapPlacement = reactive([{
"value": 1, "label": 'Left to Right'
}, {"value": 2, "label": 'Serpentine'}])
const sizeRestrict = reactive([{
"value": 0, "label": 'None'
}, {
"value": 1, "label": 'Multiple of Plots Wide'
}, {
"value": 2, "label": 'Exact'
}])
const patternRules = {
xVal: [
{
required: true,
message: '内容不能为空',
},
],
yVal: [
{
required: true,
message: '内容不能为空',
},
],
checkOption: [
{
required: true,
message: '内容不能为空',
},
],
setVal: [
{
required: true,
message: '内容不能为空',
},
],
minVal: [
{
required: true,
message: '内容不能为空',
},
],
maxVal: [
{
required: true,
message: '内容不能为空',
},
],
}
const rules = {
templateName: [
{
required: true,
message: '模板名称不能为空',
},
],
numEntries: [
{
required: true,
message: '数量不能为空',
},
],
plotsWide: [
{
required: true,
message: '地块长度不能为空',
},
],
mapPlacement: [
{
required: true,
message: '种植顺序不能为空',
},
],
sizeRestriction: [
{
required: true,
message: '大小限制不能为空',
},
],
enabled: [
{
required: true,
message: '是否可用不能为空',
},
],
}
const checksNum = ref(0)
const noChecksNum = ref(0)
// 打开弹窗
const handleType = ref("")
const openDialog = async (row: any, type: any) => {
handleType.value = type
if (type == "2") {
// 查询修改的数据
const res = await getEditData({"layoutTemplateId": row.layoutTemplateId})
insertForm.value = res;
}
drawerVisible.value = true;
};
// 导出方法在父组件中进行使用
defineExpose({openDialog});
// 表单提交
const handleOk = async () => {
okLoading.value = true;
// 需要使用await,方法执行完成之后才能判断返回结果
const validRes = await formRef.value?.validate();
if (Number(insertForm.value.numEntries) < Number(insertForm.value.plotsWide)) {
Message.error({content: 'The number of entries cannot be less than the plots wide', position: 'top'});
return
}
if (!validRes) {
try {
let formData = insertForm.value;
const mapInfo = map.value.filter((item: { entryNum: number; checkNum: string; regionNum: string; }) => item.entryNum && (item.checkNum || item.regionNum != 'None'))
let mapList = []
for (let ele of mapInfo) {
let info = {...ele}
if (info.regionNum == 'None') {
info.regionNum = '0'
}
mapList.push(info)
}
await addEdit({"template": formData, "map": mapList});
drawerVisible.value = false;
templateVisible.value = false;
insertForm.value = insertFormData()
checksNum.value = 0
noChecksNum.value = 0
// setTimeout(() => map.value = [], 50)
Message.success({content: '操作成功', position: 'top'});
// 调用父组件方法进行画面刷新
emits('handleQuery');
} catch (e) {
console.log("执行失败," + JSON.stringify(e))
} finally {
okLoading.value = false;
}
} else {
okLoading.value = false;
}
};
// 取消
const handleCancel = () => {
insertForm.value = insertFormData();
drawerVisible.value = false;
// 调用父组件方法进行画面刷新
// emits('handleQuery');
}
const originalData = ref([] as any)
const handleNext = async () => {
map.value = []
const validRes = await formRef.value?.validate();
// entries不能小于plotwide
if (Number(insertForm.value.numEntries) < Number(insertForm.value.plotsWide)) {
Message.error({content: 'The number of entries cannot be less than the plots wide', position: 'top'});
return
}
if (!validRes) {
templateVisible.value = true
drawerVisible.value = false
// 设置颜色板
setColorData()
mapLoading.value = true
try {
if (handleType.value == '1') {
// 设置check信息
noChecksNum.value = insertForm.value.numEntries!
checksNum.value = 0
// 设置颜色数据
for (let eleColor of data.value) {
if (eleColor.region === 'None') {
eleColor.count = Number(insertForm.value.numEntries)
} else {
eleColor.count = 0
}
}
// 获取地图数据
const res = await getMapInfo({"template": insertForm.value})
// 设置地图数据
map.value = res.mapList.flatMap((item: any) => item)
// 保留原始地图数据
originalData.value = res.mapList
// 设置地图显示的行数
rows = res.rowNum
} else {
// 查询地图信息
const res = await getMapInfo({"template": insertForm.value})
// 设置地图数据
map.value = res.mapList.flatMap((item: any) => item)
// 保留原始地图数据
originalData.value = res.mapList
// 设置地图显示的行数
rows = res.rowNum
// 设置颜色信息
let colorList = res.mapColorList.filter((item: { regionNum: number; }) => item.regionNum != 0)
data.value[0].count = insertForm.value.numEntries!
for (let ele of colorList) {
let color = data.value.find((item: { region: string; }) => item.region == ele.regionNum)
color!.count++
data.value[0].count--
}
// 设置check信息
checksNum.value = res.checkNum
noChecksNum.value = insertForm.value.numEntries! - res.checkNum
}
} catch (e) {
console.log(e)
} finally {
mapLoading.value = false
}
}
}
let isMouseDown = false;
let startIndex = 0;
const mouseDownEvent = (index: number) => {
console.log("mouseDown:" + index)
isMouseDown = true
startIndex = index
const divInfo = 'div' + index; // 动态生成 ID
const divElement = document.getElementById(divInfo); // 通过 ID 获取元素
divElement!.style.border = '2px solid'
}
const mouseOverEvent = (index: number) => {
console.log("mouseOver:" + index)
if (isMouseDown) {
const currentIndex = index;
// 计算选中区域的起点和终点
const [start, end] = startIndex < currentIndex ?
[startIndex, currentIndex] : [currentIndex, startIndex];
// 清除之前的选中状态
// 选中区域
for (let i = start; i <= end; i++) {
const rowStart = Math.floor(startIndex / (insertForm.value.plotsWide! + 1));
const colStart = startIndex % (insertForm.value.plotsWide! + 1);
const rowEnd = Math.floor(currentIndex / (insertForm.value.plotsWide! + 1));
const colEnd = currentIndex % (insertForm.value.plotsWide! + 1);
for (let r = Math.min(rowStart, rowEnd); r <= Math.max(rowStart, rowEnd); r++) {
for (let c = Math.min(colStart, colEnd); c <= Math.max(colStart, colEnd); c++) {
const selectedIndex = r * (insertForm.value.plotsWide! + 1) + c; // 计算该行列在 gridItems 中的索引
if (selectedIndex >= 0) {
const divInfo = 'div' + selectedIndex; // 动态生成 ID
const divElement = document.getElementById(divInfo); // 通过 ID 获取元素
divElement!.style.border = '2px solid'
}
}
}
}
}
}
const mouseUpEvent = (index: number) => {
console.log("mouseUp:" + index)
isMouseDown = false; // 鼠标抬起时重置状态
}
const handlePrev = () => {
drawerVisible.value = true
templateVisible.value = false
checksNum.value = 0
noChecksNum.value = 0
// setTimeout(() => map.value = [], 50)
}
const handleCancelMap = () => {
templateVisible.value = false
insertForm.value = insertFormData();
checksNum.value = 0
noChecksNum.value = 0
// setTimeout(() => map.value = [], 50)
}
const map = ref([] as any)
const selectedKeys = ref([] as any);
const rowSelection = reactive({
type: 'radio'
});
const columns = [
{
title: 'Region',
dataIndex: 'region',
},
{
title: 'Count',
dataIndex: 'count',
},
];
const data = ref([] as any)
const setColorData = () => {
data.value = [
{
region: 'None',
count: 0,
color: '#ffffff',
}, {
region: '1',
count: 0,
color: '#ffc0cb',
}, {
region: '2',
count: 0,
color: '#add8e6',
}, {
region: '3',
count: 0,
color: '#90ee90',
}, {
region: '4',
count: 0,
color: '#ffff00',
}, {
region: '5',
count: 0,
color: '#f5f5dc',
}, {
region: '6',
count: 0,
color: '#00ffff',
}, {
region: '7',
count: 0,
color: '#ffa07a',
}, {
region: '8',
count: 0,
color: '#eee8aa',
}, {
region: '9',
count: 0,
color: '#ff0000',
}, {
region: '10',
count: 0,
color: '#0000ff',
}, {
region: '11',
count: 0,
color: '#008000',
}, {
region: '12',
count: 0,
color: '#ffa500',
}]
}
const titleColorList = [
{
region: '21',
color: '#ececec',
}, {
region: '22',
color: '#d3d3d3',
}
]
// 设置颜色时,获取选择数据的下标
const selIndex = ref("")
const oldData = ref({} as any)
const inputClick = (index: string) => {
// 设置div的选中效果
// 将之前选择的div的样式还原
if (selIndex.value) {
const oldDiv = 'div' + selIndex.value; // 动态生成 ID
const oldEle = document.getElementById(oldDiv); // 通过 ID 获取元素
oldEle!.style.border = '1px solid #ccc'
}
// 对选中的div进行样式设置
const divInfo = 'div' + index; // 动态生成 ID
const divElement = document.getElementById(divInfo); // 通过 ID 获取元素
divElement!.style.border = '2px solid'
selIndex.value = index
// 获取修改之前的值
oldData.value = {...map.value[selIndex.value]}
}
const changeVal = (index: string) => {
// 如果旧值为空,新值为空,则不更新check信息;
// 如果旧值为空,新增不为空,则更新check信息;
// 如果旧值不为空,新值为空,则更新check信息;
// 如果旧值不为空,新值不为空,则不更新check信息
// 获取新值
const newData = map.value[index]
// 数值校验
const regex = /^[1-9]\d*$/;
if (newData.checkNum && !regex.test(newData.checkNum)) {
Message.error({content: 'checkNo必须是正整数', position: 'top'});
newData.checkNum = ''
return
}
if (!oldData.value.checkNum && newData.checkNum) {
checksNum.value++
noChecksNum.value--
} else if (oldData.value.checkNum && !newData.checkNum) {
checksNum.value--
noChecksNum.value++
}
}
// 选择颜色后,调用设置方法
const setColor = () => {
// 校验
if (!selIndex.value) {
Message.error({content: '请选择要设置颜色的区域', position: 'top'});
return
}
if (selectedKeys.value.length === 0) {
Message.error({content: '请选择要设置的颜色', position: 'top'});
return
}
// 获取选择的div元素
const inputId = 'input' + selIndex.value; // 动态生成 ID
const inputElement = document.getElementById(inputId); // 通过 ID 获取元素
// 获取原来的颜色
let selItem = map.value[selIndex.value]
if (selItem.regionNum != selectedKeys.value[0]) {
// 原颜色数量减1
let oldColor = data.value.find((item: { region: string; }) => item.region == selItem.regionNum)
oldColor!.count--
// 新颜色数量+1
const newColor = data.value.find((item: { region: string; }) => item.region == selectedKeys.value[0])
newColor!.count++
// 对选中的div进行颜色设置
inputElement!.style.backgroundColor = newColor!.color
// 将新颜色进行保存
selItem.regionNum = selectedKeys.value[0]
}
// 设置完成之后清空
selectedKeys.value = []
}
// 分割数组
const splitArray = (arr: any, chunkSize: number) => {
const result = [];
for (let i = 0; i < arr.length; i += chunkSize) {
result.push(arr.slice(i, i + chunkSize));
}
return result;
}
//设置地图数据
let rows = 0;
const setInsData = (formData: any) => {
// 将数据按照小区数进行分割,如果最后一个集合的长度小于小区数,则补充X直至等于小区数。
// 如果种植规则是left to right,则直接返回,如果是龙摆尾则对偶数行进行顺序反转
let dataList = []
for (let i = 1; i <= formData.numEntries; i++) {
dataList.push({'entryNum': i, 'checkNum': '', 'regionNum': 'None', 'disable': '0'})
}
let splitList = splitArray(dataList, formData.plotsWide)
let splitLength = splitList.length
// 补充地图
let len = splitList[splitLength - 1].length
if (len != formData.plotsWide) {
for (let i = len; i < formData.plotsWide; i++) {
splitList[splitLength - 1].push({'entryNum': '', 'checkNum': 'X', 'regionNum': '22', 'disable': '1'})
}
}
// 设置走向
if (formData.mapPlacement == '2') {
for (let i = 0; i < splitList.length; i++) {
if ((i + 1) % 2 == 0) {
splitList[i].reverse()
}
splitList[i].unshift({'entryNum': '', 'checkNum': String(i + 1), 'regionNum': '21', 'disable': '1'})
}
} else if (formData.mapPlacement == '1') {
for (let i = 0; i < splitList.length; i++) {
splitList[i].unshift({'entryNum': '', 'checkNum': String(i + 1), 'regionNum': '21', 'disable': '1'})
}
}
let titleArr = []
for (let i = 0; i <= formData.plotsWide; i++) {
titleArr.push({'entryNum': '', 'checkNum': i == 0 ? '' : String(i), 'regionNum': '21', 'disable': '1'})
}
splitList.push(titleArr)
splitList.reverse()
rows = splitList.length
return splitList.flatMap(item => item)
}
const setDefaultColor = (regionNum: string) => {
const color = data.value.find((item: { region: string; }) => item.region == regionNum)
if (color) {
return {backgroundColor: color!.color};
} else {
// const titleColor = titleColorList.find(item => item.region == regionNum)
return {backgroundColor: '#ececec'};
}
}
const checkRatio = computed(() => {
return (checksNum.value / Number(insertForm.value.numEntries)).toFixed(3)
})
// 页面加载时,设置页面中每行显示的位数
const setGridTemplateColumns = () => {
return {
display: 'grid',
gridTemplateColumns: `repeat(${insertForm.value.plotsWide! + 1}, minmax(50px, 50px))`,
gridTemplateRows: `repeat(${rows}, minmax(70px, 70px))`,
// gridRowGap: '1px'
};
}
// 斜对角放置
const handlePattern = () => {
// 必须选择起始位置
if (!selIndex.value) {
Message.error({content: '请选择起始位置', position: 'top'});
return
}
patternVisible.value = true
}
// 清空checks
const handleClearChecks = async () => {
mapLoading.value = true;
try {
map.value.forEach((item: { entryNum: any; checkNum: string; }) => {
if (item.entryNum) {
item.checkNum = ''
}
})
// 设置check信息
checksNum.value = 0
noChecksNum.value = 0
// 清空颜色信息
await handleClearRegions()
} finally {
mapLoading.value = false
}
}
// 清空所有的颜色
const handleClearRegions = () => {
mapLoading.value = true;
try {
map.value.forEach((item: { entryNum: any; regionNum: string; }) => {
if (item.entryNum) {
item.regionNum = 'None'
}
})
// 清空颜色信息
setColorData()
data.value[0].count = insertForm.value.numEntries!
} finally {
mapLoading.value = false
}
}
// 设置对角放置
const patternOk = async () => {
// 表单校验处理
const validateRes = await patternFormRef.value.validate()
if (validateRes) {
return
}
patternVisible.value = false
mapLoading.value = true;
try {
// 根据起始位置查找entry no
const selData = map.value[selIndex.value]
if (patternData.value.checkOption === 1) {
selData.checkNum = patternData.value.setVal.toString()
} else {
selData.checkNum = getRandomInteger(patternData.value.minVal, patternData.value.maxVal).toString()
}
// 行下标
let selRowIndex: number = 0
// 列下标
let selColIndex: number = 0
for (let i = 0; i < originalData.value.length; i++) {
const index = originalData.value[i].findIndex((item: { entryNum: any; }) => item.entryNum == selData.entryNum)
if (index >= 0) {
selRowIndex = i
selColIndex = index
break
}
}
if (selRowIndex == 0) {
return
}
for (let i = selRowIndex - patternData.value.yVal; i >= 1; i = i - patternData.value.yVal) {
selColIndex = selColIndex + patternData.value.xVal
if (selColIndex > insertForm.value.plotsWide!) {
break
}
let next = originalData.value[i][selColIndex]
let data = map.value.find((x: { entryNum: number; }) => x.entryNum == next.entryNum)
if (patternData.value.checkOption === 1) {
data.checkNum = patternData.value.setVal.toString()
} else {
data.checkNum = getRandomInteger(patternData.value.minVal, patternData.value.maxVal).toString()
}
}
const checks = map.value.filter((x: {
entryNum: any; checkNum: any;
}) => x.entryNum && x.checkNum).length
checksNum.value = checks
noChecksNum.value = insertForm.value.numEntries! - checks
} finally {
mapLoading.value = false;
}
}
// 生成随机数
const getRandomInteger = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const patternCancel = () => {
patternVisible.value = false
patternData.value = patternFormData()
}
// 组件完成初始渲染并创建 DOM 节点后运行
// onMounted(async () => {
// await getLocationInfo()
// })
</script>
<style scoped>
.container {
padding: 0px 20px 20px 0px; /* 整体内边距 */
width: 100%;
height: 620px;
overflow: auto;
}
.input-wrapper {
width: 50px;
height: 70px;
padding: 0px 0px 0px 0px; /* 内边距 */
border: 1px solid #ccc; /* 边框 */
/*margin-bottom: 1px;*/
/*margin-top: 1px;*/
/*border-radius: 5px; !* 圆角 *!*/
}
.input {
width: 100%; /* 输入框占满父容器 */
height: 100%;
border: 1px; /* 移除默认边框 */
font-weight: bold;
/*outline: none; !* 移除聚焦时的轮廓 *!*/
}
:deep .arco-input-wrapper {
padding-right: 1px;
padding-left: 1px
}
</style>
4.总结
注意列数及行数的设置
注意列宽及行高的设置
注意行间距及列间距的设置