automated_admin/src/modules/fixtures/components/assembly/rubik-cube.vue
2025-01-09 16:40:36 +08:00

454 lines
8.0 KiB
Vue

<template>
<div class="assembly-rubik-cube">
<div class="w-120">显示模式</div>
<el-radio-group v-model="value.mode" @change="changeGroup">
<el-radio v-for="mode in modes" :key="mode.type" :value="mode.type">
{{ mode.label }}
</el-radio>
</el-radio-group>
<div class="w-120">图片间隔</div>
<assembly-slider
v-model="value.gap"
:min="0"
:max="40"
unit="rpx"
:step="1"
@change="changeSlider"
/>
<div
class="box"
:class="[`is-${value.mode}`]"
:style="{ gap: `${value.gap / 2}px`, '--gap': `${value.gap / 2}px` }"
>
<div
class="item"
v-for="(item, index) in value.list"
:key="index"
:class="[`is-${value.mode}-item-${index}`]"
@click="onTap(index)"
>
<div class="circle" v-if="activate === index">
<el-icon :size="20" color="#4165d7">
<circle-check-filled />
</el-icon>
</div>
<div class="tips" v-if="!item.icon">
{{ item.tips }}
</div>
<el-image class="icon" :src="item.icon" fit="fill" v-else></el-image>
</div>
</div>
<div class="upload">
<div class="upload-box">
<cl-upload
text="上传图片"
v-model="value.list[activate].icon"
@success="onChange"
:size="[80, 80]"
/>
<div class="link">
<assembly-link
v-model="value.list[activate].link"
:prepend="false"
@change="onChange"
/>
<div class="tips">{{ value.list[activate].tips }}</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup name="assembly-rubik-cube">
import { ref, type PropType } from "vue";
import { Form } from "../../types/form";
import { CircleCheckFilled } from "@element-plus/icons-vue";
const props = defineProps({
modelValue: {
type: Object as PropType<Form.RubikCube>,
default: () => ({
mode: "mode-1",
gap: 0,
list: [
{
icon: "",
tips: "宽度375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽度375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
}
]
})
}
});
const emit = defineEmits(["update:modelValue"]);
const value = ref(props.modelValue);
const modes: Form.RubikCubeMode[] = [
{
type: "mode-1",
label: "一行两个",
list: [
{
icon: "",
tips: "宽度375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽度375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
}
]
},
{
type: "mode-2",
label: "一行三个",
list: [
{
icon: "",
tips: "宽度250",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽度250",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽度250",
link: {
name: "",
type: "",
appid: "",
page: ""
}
}
]
},
{
type: "mode-3",
label: "左一右二",
list: [
{
icon: "",
tips: "宽375\n高750",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽375\n高375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽375\n高375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
}
]
},
{
type: "mode-4",
label: "上一下二",
list: [
{
icon: "",
tips: "宽750\n高375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽375\n高375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
},
{
icon: "",
tips: "宽375\n高375",
link: {
name: "",
type: "",
appid: "",
page: ""
}
}
]
}
];
const activate = ref(0);
function changeGroup(mode: any) {
const selectedMode = modes.find((m) => m.type === mode);
if (selectedMode) {
value.value.list = selectedMode.list;
activate.value = 0;
changeSlider(value.value.gap);
onChange();
}
}
function onTap(index: number) {
activate.value = index;
}
// 图片间隔
function changeSlider(val: number) {
switch (value.value.mode) {
case "mode-1":
// 一行两个
value.value.list.forEach((e) => {
const width = 375;
e.tips = `宽度${width - (val ? val / 2 : 0)}\n高度不限`;
});
break;
case "mode-2":
// 一行三个
value.value.list.forEach((e) => {
const width = 250;
e.tips = `宽度${width - (val ? Math.floor(val / 3) : 0)}\n高度不限`;
});
break;
case "mode-3":
// 左一右二
value.value.list.forEach((e, index) => {
const width = 375;
const w = width - (val ? Math.floor(val / 2) : 0);
e.tips = index ? `${w}\n高度不限` : `${w}\n高度不限`;
});
break;
case "mode-4":
value.value.list.forEach((e, index) => {
if (index) {
const width = 375;
const w = width - (val ? Math.floor(val / 2) : 0);
e.tips = `${w}\n高度不限`;
} else {
e.tips = `宽750\n高度不限`;
}
});
break;
default:
break;
}
value.value.list;
}
function onChange() {
emit("update:modelValue", value.value);
}
</script>
<style lang="scss" scoped>
.assembly-rubik-cube {
.w-120 {
width: 120px;
}
.box {
display: flex;
margin-top: 10px;
.item {
display: flex;
align-items: center;
justify-content: center;
min-height: 100px;
background-color: lightblue;
box-sizing: border-box;
cursor: pointer;
position: relative;
.icon {
width: 100%;
max-width: 100%;
border: 0;
vertical-align: middle;
}
.tips {
font-size: 14px;
text-align: center;
white-space: pre-line;
}
.circle {
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
}
}
}
.is-mode-1 {
display: grid;
grid-template-columns: repeat(2, 1fr);
.item {
&.is-mode-1-item-0 {
min-height: calc(150px - var(--gap) / 2);
background-color: lightgreen;
}
&.is-mode-1-item-1 {
min-height: calc(150px - var(--gap) / 2);
background-color: lightcoral;
}
}
}
.is-mode-2 {
display: grid;
grid-template-columns: repeat(3, 1fr);
.item {
&.is-mode-2-item-0 {
min-height: calc(100px - var(--gap) / 3);
}
&.is-mode-2-item-1 {
min-height: calc(100px - var(--gap) / 3);
background-color: lightgreen;
}
&.is-mode-2-item-2 {
min-height: calc(100px - var(--gap) / 3);
background-color: lightcoral;
}
}
}
.is-mode-3 {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
.item {
&.is-mode-3-item-0 {
min-height: 300px;
grid-column: 1 / 2;
grid-row: 1 / 3;
background-color: lightblue;
}
&.is-mode-3-item-1 {
min-height: calc(150px - var(--gap) / 2);
grid-column: 2 / 3;
grid-row: 1 / 2;
background-color: lightgreen;
}
&.is-mode-3-item-2 {
min-height: calc(150px - var(--gap) / 2);
grid-column: 2 / 3;
grid-row: 2 / 3;
background-color: lightcoral;
}
}
}
.is-mode-4 {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto;
.item {
&.is-mode-4-item-0 {
min-height: calc(150px - var(--gap) / 2);
grid-column: 1 / 3;
grid-row: 1 / 2;
background-color: lightblue;
}
&.is-mode-4-item-1 {
min-height: calc(150px - var(--gap) / 2);
grid-column: 1 / 2;
grid-row: 2 / 3;
background-color: lightgreen;
}
&.is-mode-4-item-2 {
min-height: calc(150px - var(--gap) / 2);
grid-column: 2 / 3;
grid-row: 2 / 3;
background-color: lightcoral;
}
}
}
.upload {
margin-top: 20px;
box-sizing: border-box;
background-color: #f6f7fa;
border-radius: 10px;
padding: 6px;
margin-bottom: 10px;
.upload-box {
display: flex;
background-color: #ffffff;
padding: 10px;
border-radius: 6px;
.link {
margin-left: 10px;
}
.tips {
font-size: 14px;
margin-top: 10px;
color: var(--el-color-warning);
text-align: center;
}
}
}
}
</style>