|
@@ -0,0 +1,260 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="image-cube-setting setting">
|
|
|
|
|
+ <template v-if="tabType == 'data'">
|
|
|
|
|
+ <div class="card">
|
|
|
|
|
+ <div class="title">魔方样式 <div class="tip">每格尺寸:187*187</div></div>
|
|
|
|
|
+ <div class="content">
|
|
|
|
|
+ <table class="image-cube-map">
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ <tr v-for="trItem in mapList" :key="trItem">
|
|
|
|
|
+ <td
|
|
|
|
|
+ class="map-item"
|
|
|
|
|
+ :class="
|
|
|
|
|
+ activeData.minRow <= trItem &&
|
|
|
|
|
+ trItem <= activeData.maxRow &&
|
|
|
|
|
+ activeData.minCol <= tdItem &&
|
|
|
|
|
+ tdItem <= activeData.maxCol
|
|
|
|
|
+ ? 'map-item--active'
|
|
|
|
|
+ : ''
|
|
|
|
|
+ "
|
|
|
|
|
+ :style="{
|
|
|
|
|
+ width: scale + 'px',
|
|
|
|
|
+ height: scale + 'px',
|
|
|
|
|
+ }"
|
|
|
|
|
+ v-for="tdItem in mapList"
|
|
|
|
|
+ :key="tdItem"
|
|
|
|
|
+ @click.stop="selectItem(trItem, tdItem)"
|
|
|
|
|
+ @mouseover="onMouseover(trItem, tdItem)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-icon>
|
|
|
|
|
+ <Plus />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="position-item sa-flex sa-row-center"
|
|
|
|
|
+ :class="selected.active == sindex ? 'position-item--active' : ''"
|
|
|
|
|
+ v-for="(style, sindex) in selected.data"
|
|
|
|
|
+ :style="{
|
|
|
|
|
+ width: style.width * scale + 'px',
|
|
|
|
|
+ height: style.height * scale + 'px',
|
|
|
|
|
+ top: style.top * scale + 'px',
|
|
|
|
|
+ left: style.left * scale + 'px',
|
|
|
|
|
+ }"
|
|
|
|
|
+ :key="style"
|
|
|
|
|
+ @mouseover="onCancelSelect"
|
|
|
|
|
+ @click.stop="onPositionSelect(sindex)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ style.width }}*{{ style.height }}
|
|
|
|
|
+ <el-icon class="close" @click.stop="deleteItem(sindex)">
|
|
|
|
|
+ <CircleCloseFilled />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ <template v-if="selected.data.length > 0">
|
|
|
|
|
+ <el-form-item label="上传图片">
|
|
|
|
|
+ <sa-uploader
|
|
|
|
|
+ v-model="selected.data[selected.active].src"
|
|
|
|
|
+ fileType="image"
|
|
|
|
|
+ ></sa-uploader>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="链接">
|
|
|
|
|
+ <dc-url v-model="selected.data[selected.active].url"></dc-url>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <el-form-item label="上圆角">
|
|
|
|
|
+ <dc-slider v-model="settingData.data.borderRadiusTop"></dc-slider>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="下圆角">
|
|
|
|
|
+ <dc-slider v-model="settingData.data.borderRadiusBottom"></dc-slider>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="间距">
|
|
|
|
|
+ <dc-slider v-model="settingData.data.space"></dc-slider>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+ import { reactive, ref, watch } from 'vue';
|
|
|
|
|
+ import { cloneDeep } from 'lodash';
|
|
|
|
|
+ import dcSlider from '../../common/dc-slider.vue';
|
|
|
|
|
+ import dcUrl from '../../common/dc-url.vue';
|
|
|
|
|
+
|
|
|
|
|
+ const props = defineProps(['settingData', 'tabType']);
|
|
|
|
|
+
|
|
|
|
|
+ watch(() => props.settingData, () => {
|
|
|
|
|
+ selected.data = props.settingData.data.list || [];
|
|
|
|
|
+ selected.active = props.settingData.data.list.length > 0 ? 0 : null;
|
|
|
|
|
+ }, {
|
|
|
|
|
+ deep: true
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const scale = ref(66);
|
|
|
|
|
+ const mapList = [1, 2, 3, 4];
|
|
|
|
|
+ const start = reactive({ row: 0, col: 0 });
|
|
|
|
|
+ const selectFlag = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+ const activeData = reactive({
|
|
|
|
|
+ width: 0,
|
|
|
|
|
+ height: 0,
|
|
|
|
|
+ top: 0,
|
|
|
|
|
+ left: 0,
|
|
|
|
|
+ minRow: 0,
|
|
|
|
|
+ maxRow: 0,
|
|
|
|
|
+ minCol: 0,
|
|
|
|
|
+ maxCol: 0,
|
|
|
|
|
+ src: '',
|
|
|
|
|
+ url: '',
|
|
|
|
|
+ });
|
|
|
|
|
+ let selected = reactive({
|
|
|
|
|
+ data: props.settingData.data.list || [],
|
|
|
|
|
+ active: props.settingData.data.list.length > 0 ? 0 : null,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ function selectItem(row, col) {
|
|
|
|
|
+ // 开始的坐标
|
|
|
|
|
+ if (!selectFlag.value) {
|
|
|
|
|
+ start.row = row;
|
|
|
|
|
+ start.col = col;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 结束存储数据
|
|
|
|
|
+ if (selectFlag.value) {
|
|
|
|
|
+ selected.data.push(cloneDeep(activeData));
|
|
|
|
|
+ selected.active = selected.data.length - 1;
|
|
|
|
|
+ clearActiveData();
|
|
|
|
|
+ updatelist();
|
|
|
|
|
+ }
|
|
|
|
|
+ selectFlag.value = !selectFlag.value;
|
|
|
|
|
+ onMouseover(row, col);
|
|
|
|
|
+ }
|
|
|
|
|
+ function onMouseover(row, col) {
|
|
|
|
|
+ if (selectFlag.value) {
|
|
|
|
|
+ let squaresArr = [
|
|
|
|
|
+ start.row + '*' + start.col,
|
|
|
|
|
+ row + '*' + col,
|
|
|
|
|
+ start.row + '*' + col,
|
|
|
|
|
+ row + '*' + start.col,
|
|
|
|
|
+ ];
|
|
|
|
|
+ let min = squaresArr.sort()[0].split('*');
|
|
|
|
|
+ let max = squaresArr.sort()[3].split('*');
|
|
|
|
|
+ // 面积不可重叠
|
|
|
|
|
+ const flag = selected.data.some((f) => {
|
|
|
|
|
+ return isOverlap(f, {
|
|
|
|
|
+ width: Math.abs(start.col - col) + 1,
|
|
|
|
|
+ height: Math.abs(start.row - row) + 1,
|
|
|
|
|
+ left: min[1] - 1,
|
|
|
|
|
+ top: min[0] - 1,
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ if (!flag) {
|
|
|
|
|
+ // 宽高
|
|
|
|
|
+ activeData.width = Math.abs(start.col - col) + 1;
|
|
|
|
|
+ activeData.height = Math.abs(start.row - row) + 1;
|
|
|
|
|
+ // 定位
|
|
|
|
|
+ activeData.left = min[1] - 1;
|
|
|
|
|
+ activeData.top = min[0] - 1;
|
|
|
|
|
+ // xy轴最大最小值
|
|
|
|
|
+ activeData.minRow = min[0];
|
|
|
|
|
+ activeData.minCol = min[1];
|
|
|
|
|
+ activeData.maxRow = max[0];
|
|
|
|
|
+ activeData.maxCol = max[1];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 删除选中的区域
|
|
|
|
|
+ function deleteItem(index) {
|
|
|
|
|
+ selected.data.splice(index, 1);
|
|
|
|
|
+ selected.active = selected.data.length - 1;
|
|
|
|
|
+ updatelist();
|
|
|
|
|
+ }
|
|
|
|
|
+ // 取消选中区域
|
|
|
|
|
+ function onCancelSelect() {
|
|
|
|
|
+ selectFlag.value = false;
|
|
|
|
|
+ clearActiveData();
|
|
|
|
|
+ }
|
|
|
|
|
+ function onPositionSelect(index) {
|
|
|
|
|
+ selected.active = index;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 提交
|
|
|
|
|
+ function updatelist() {
|
|
|
|
|
+ let deleteData = ['minRow', 'maxRow', 'minCol', 'maxCol'];
|
|
|
|
|
+ let tempData = [];
|
|
|
|
|
+ selected.data.forEach((s) => {
|
|
|
|
|
+ let obj = s;
|
|
|
|
|
+ deleteData.forEach((d) => {
|
|
|
|
|
+ delete obj[d];
|
|
|
|
|
+ });
|
|
|
|
|
+ tempData.push(obj);
|
|
|
|
|
+ });
|
|
|
|
|
+ props.settingData.data.list = tempData;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 清除activeData数据
|
|
|
|
|
+ function clearActiveData() {
|
|
|
|
|
+ for (var a in activeData) {
|
|
|
|
|
+ activeData[a] = 0;
|
|
|
|
|
+ if (a == 'src' || a == 'url') {
|
|
|
|
|
+ activeData[a] = '';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 选择面积不可重叠
|
|
|
|
|
+ function isOverlap(obj1, obj2) {
|
|
|
|
|
+ const l1 = { x: obj1.left, y: obj1.top };
|
|
|
|
|
+ const r1 = { x: obj1.left + obj1.width, y: obj1.top + obj1.height };
|
|
|
|
|
+ const l2 = { x: obj2.left, y: obj2.top };
|
|
|
|
|
+ const r2 = { x: obj2.left + obj2.width, y: obj2.top + obj2.height };
|
|
|
|
|
+ if (l1.x >= r2.x || l2.x >= r1.x || l1.y >= r2.y || l2.y >= r1.y) return false;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+ .image-cube-setting {
|
|
|
|
|
+ .image-cube-map {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ margin: 0 auto 16px;
|
|
|
|
|
+ border-spacing: 0;
|
|
|
|
|
+ border-collapse: collapse;
|
|
|
|
|
+ .map-item {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ border: 1px solid var(--sa-border);
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ .el-icon {
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ color: var(--sa-place);
|
|
|
|
|
+ }
|
|
|
|
|
+ &--active {
|
|
|
|
|
+ background-color: var(--sa-background-hex-hover);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .position-item {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ background: var(--sa-background-hex-active);
|
|
|
|
|
+ border: 1px solid var(--el-color-primary);
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ .close {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: var(--el-color-primary);
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: -6px;
|
|
|
|
|
+ right: -6px;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ }
|
|
|
|
|
+ &--active {
|
|
|
|
|
+ background: var(--sa-background-hex-active);
|
|
|
|
|
+ border: 1px solid var(--el-color-primary);
|
|
|
|
|
+ .close {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+</style>
|