You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
8.2 KiB
302 lines
8.2 KiB
<script setup lang="ts">
|
|
import { computed, reactive } from "vue";
|
|
import { ElButton, ElDivider, ElFormItem, ElIcon, ElInputNumber, useFormItem } from "element-plus";
|
|
import { CopyDocument, Delete } from "@element-plus/icons-vue";
|
|
import { Typeof } from "@ease-forge/shared";
|
|
|
|
defineOptions({
|
|
name: 'BayEditor',
|
|
});
|
|
|
|
interface DtBay {
|
|
/** 列的宽度 */
|
|
bayWidth: number;
|
|
/** 列偏移 */
|
|
offset: number;
|
|
/** 每层的高度 */
|
|
levelHeight: Array<number>;
|
|
}
|
|
|
|
type DtBays = Array<DtBay>;
|
|
|
|
// 组件事件定义
|
|
const emit = defineEmits<{
|
|
/** 更新内联表格数据 */
|
|
"update:modelValue": [value: DtBays];
|
|
}>();
|
|
|
|
|
|
// 定义 Props 类型
|
|
interface BayEditorProps {
|
|
modelValue: DtBays;
|
|
}
|
|
|
|
// 读取组件 props 属性
|
|
const props = withDefaults(defineProps<BayEditorProps>(), {});
|
|
|
|
// 定义 State 类型
|
|
interface BayEditorState {
|
|
numberOfBays: number;
|
|
numberOfLevels: number;
|
|
widthOfBays: number;
|
|
heightOfLevels: number;
|
|
selectIdx?: number;
|
|
}
|
|
|
|
// state 属性
|
|
const state = reactive<BayEditorState>({
|
|
numberOfBays: props.modelValue?.length ?? 1,
|
|
numberOfLevels: props.modelValue?.[0]?.levelHeight?.length ?? 1,
|
|
widthOfBays: props.modelValue?.[0]?.bayWidth ?? 1,
|
|
heightOfLevels: props.modelValue?.[0]?.levelHeight?.length ?? 1,
|
|
});
|
|
|
|
// 定义 Data 类型
|
|
interface BayEditorData {
|
|
labelWidth: number;
|
|
}
|
|
|
|
// 内部数据
|
|
const data: BayEditorData = {
|
|
labelWidth: 110,
|
|
};
|
|
const { formItem } = useFormItem();
|
|
const list = computed(() => props.modelValue ?? []);
|
|
const selectDay = computed(() => {
|
|
if (Typeof.noValue(state.selectIdx)) return;
|
|
return props.modelValue?.[state.selectIdx];
|
|
});
|
|
|
|
function setSelectIdx(idx: number) {
|
|
state.selectIdx = idx;
|
|
}
|
|
|
|
function applyBasicSettings() {
|
|
|
|
}
|
|
|
|
function deleteBay() {
|
|
|
|
}
|
|
|
|
function copyBay() {
|
|
|
|
}
|
|
|
|
interface BayEditorExpose {
|
|
state: BayEditorState;
|
|
data: BayEditorData;
|
|
}
|
|
|
|
const expose: BayEditorExpose = {
|
|
state,
|
|
data,
|
|
};
|
|
// 定义组件公开内容
|
|
defineExpose(expose);
|
|
|
|
export type {
|
|
BayEditorProps,
|
|
BayEditorState,
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="bay-editor">
|
|
<ElDivider class="bay-editor-title" contentPosition="left">Basic</ElDivider>
|
|
<div class="flex-column-container bay-editor-basic" style="gap: 8px;">
|
|
<div class="flex-row-container">
|
|
<ElFormItem label="Number of Bays" :labelWidth="data.labelWidth">
|
|
<ElInputNumber :controls="false" v-model="state.numberOfBays"/>
|
|
</ElFormItem>
|
|
<ElFormItem label="Number of Levels" :labelWidth="data.labelWidth">
|
|
<ElInputNumber :controls="false" v-model="state.numberOfLevels"/>
|
|
</ElFormItem>
|
|
</div>
|
|
<div class="flex-row-container">
|
|
<ElFormItem label="Width of Bays" :labelWidth="data.labelWidth">
|
|
<ElInputNumber :controls="false" v-model="state.widthOfBays"/>
|
|
</ElFormItem>
|
|
<ElFormItem label="Height of Levels" :labelWidth="data.labelWidth">
|
|
<ElInputNumber :controls="false" v-model="state.heightOfLevels"/>
|
|
</ElFormItem>
|
|
</div>
|
|
<div class="flex-row-container">
|
|
<div style="width: 248px;"/>
|
|
<ElButton size="small" @click="applyBasicSettings">Apply Basic Settings</ElButton>
|
|
</div>
|
|
</div>
|
|
<ElDivider class="bay-editor-title" contentPosition="left">Advanced</ElDivider>
|
|
<div class="flex-row-container bay-editor-advanced">
|
|
<div class="flex-item-fixed flex-column-container bay-editor-bay-list">
|
|
<div class="flex-item-fixed tools-button-container">
|
|
<ElIcon :class="['tools-button-icon', { 'tools-button-disabled': false }]" @click="copyBay">
|
|
<CopyDocument/>
|
|
</ElIcon>
|
|
<ElIcon :class="['tools-button-icon', { 'tools-button-disabled': false }]" @click="deleteBay">
|
|
<Delete/>
|
|
</ElIcon>
|
|
</div>
|
|
<div class="flex-item-fill bay-editor-bay-list-name">
|
|
<div
|
|
v-for="(item, idx) in list"
|
|
:class="[
|
|
'list-item',
|
|
{
|
|
'list-item-select': state.selectIdx === idx,
|
|
},
|
|
]"
|
|
@click="setSelectIdx(idx)"
|
|
>
|
|
{{ `Bay ${idx + 1}` }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="flex-item-fill flex-column-container bay-editor-bay-info">
|
|
<template v-if="selectDay">
|
|
<div class="flex-item-fixed">
|
|
<ElFormItem label="Bay Width" :labelWidth="80">
|
|
<ElInputNumber :controls="false" :modelValue="selectDay.bayWidth"/>
|
|
</ElFormItem>
|
|
<div style="height: 8px;"/>
|
|
<ElFormItem label="Bay Offset" :labelWidth="80">
|
|
<ElInputNumber :controls="false" :modelValue="selectDay.offset"/>
|
|
</ElFormItem>
|
|
</div>
|
|
<div>Level Heights</div>
|
|
<div class="flex-item-fill bay-editor-bay-info-level-height">
|
|
<ElFormItem
|
|
v-for="(levelHeight, idx) in selectDay.levelHeight"
|
|
:label="`Level ${idx+1}`"
|
|
:labelWidth="64"
|
|
>
|
|
<ElInputNumber :controls="false" :modelValue="levelHeight"/>
|
|
</ElFormItem>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.bay-editor {
|
|
width: 100%;
|
|
}
|
|
|
|
.bay-editor-title {
|
|
height: 12px;
|
|
user-select: none;
|
|
}
|
|
|
|
.bay-editor-basic :deep(.el-input-number) {
|
|
width: 80px;
|
|
}
|
|
|
|
.bay-editor-advanced {
|
|
height: 256px;
|
|
}
|
|
|
|
.bay-editor-bay-list {
|
|
width: 72px;
|
|
}
|
|
|
|
.bay-editor-bay-list-name {
|
|
border: 1px solid #dddddd;
|
|
}
|
|
|
|
.tools-button-container {
|
|
display: flex;
|
|
flex-direction: row;
|
|
flex-wrap: nowrap;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
cursor: pointer;
|
|
width: 100%;
|
|
}
|
|
|
|
.tools-button-container > .tools-button-icon {
|
|
color: #8c8c8c;
|
|
padding: 4px;
|
|
font-size: 22px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.tools-button-container > .tools-button-icon:hover {
|
|
color: #595959;
|
|
background-color: #d9d9d9;
|
|
}
|
|
|
|
.tools-button-container > .tools-button-icon:active {
|
|
color: #434343;
|
|
background-color: #bfbfbf;
|
|
}
|
|
|
|
.tools-button-container > .tools-button-disabled {
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.tools-button-container > .tools-button-disabled.tools-button-icon,
|
|
.tools-button-container > .tools-button-disabled.tools-button-icon:hover,
|
|
.tools-button-container > .tools-button-disabled.tools-button-icon:active {
|
|
color: #d9d9d9;
|
|
background-color: unset;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.list-item {
|
|
padding: 4px 0 4px 2px;
|
|
cursor: pointer;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
user-select: none;
|
|
color: #262626;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.list-item:hover {
|
|
background-color: #f0f0f0;
|
|
}
|
|
|
|
.list-item:active {
|
|
background-color: #dddddd;
|
|
}
|
|
|
|
.list-item.list-item-select,
|
|
.list-item.list-item-select:hover,
|
|
.list-item.list-item-select:active {
|
|
background-color: #d9d9d9;
|
|
}
|
|
|
|
.bay-editor-bay-info {
|
|
padding-left: 6px;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height {
|
|
border: 1px solid #dddddd;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height :deep(.el-input__wrapper) {
|
|
border: none;
|
|
outline: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height :deep(.el-form-item) {
|
|
border-bottom: 1px solid #dddddd;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height :deep(.el-form-item > .el-form-item__label) {
|
|
border-right: 1px solid #dddddd;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height :deep(.el-input-number) {
|
|
width: 100%;
|
|
}
|
|
|
|
.bay-editor-bay-info-level-height :deep(input[type=number].el-input__inner) {
|
|
text-align: left;
|
|
}
|
|
</style>
|
|
|