zhudie před 2 roky
rodič
revize
48d1b4188f

+ 1 - 1
package.json

@@ -66,7 +66,7 @@
     "url-join": "5.0.0",
     "vue": "3.3.4",
     "vue-hooks-plus": "1.8.6",
-    "vue-konva": "^3.0.2",
+    "vue-konva": "3.0.2",
     "vue-router": "4.1.2",
     "vue-types": "4.1.1",
     "vuedraggable": "4.1.0",

+ 3 - 0
src/views/page-config/ConfigEdit.vue

@@ -237,6 +237,8 @@
         if (!res) {
           return;
         }
+        console.log('res', res);
+
         layoutId.value = res.id;
         const layoutJSON = res.layout ? safeParse(res.layout) : null;
         if (!layoutJSON) {
@@ -277,6 +279,7 @@
 
   const filterShopList = computed(() => {
     const k = searchKey.value.trim();
+    console.log('shopList.value', shopList.value);
     if (!k) return shopList.value;
     return shopList.value?.filter((x) => x.name?.includes(k));
   });

+ 1 - 0
src/views/page-config/component/ConfigDrawer.vue

@@ -100,6 +100,7 @@
           </div>
           <hr />
           <div>
+            <!-- //这里要变选值 -->
             <div class="content-title"><div class="uploader-title">布局</div> </div>
             <div class="layout-set">
               <img src="~@/assets/icons/layout-left.png" alt="" style="margin-right: 19px" />

+ 139 - 0
src/views/page-config/component/mapContainer/LabelItem copy.vue

@@ -0,0 +1,139 @@
+<template>
+  <v-image ref="pointRef" :config="getPointCurvConfig()" />
+  <v-image ref="rectRef" :config="getRectCurConfig()" />
+  <v-text :config="getTextConfig()" />
+  <v-image :config="shineConfig" />
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, nextTick, computed, watch } from 'vue';
+  import rectBlock from '@/assets/test/2-rect.svg';
+  import pointCurv from '@/assets/test/1-curv2.svg';
+  import shine from '@/assets/test/2-shine.svg';
+  import Konva from 'konva';
+  import { MapWorkShopInfoItem } from '../../stores/useMapEditor';
+
+  const props = defineProps<{ shop: MapWorkShopInfoItem }>();
+
+  const shopData = computed(() => props.shop);
+
+  const curvImage = ref<HTMLImageElement>(new Image());
+  const rectImage = ref<HTMLImageElement>(new Image());
+  const shineImage = ref<HTMLImageElement>(new Image());
+  const rectRef = ref<Konva.Image>();
+  const pointRef = ref<Konva.Image>();
+
+  const getRGBANum = (color: string) => {
+    if (!color) return [0, 0, 0, 0];
+    const pattern = /\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)$/;
+    const array = color.match(pattern);
+    return [
+      Number(array![1]) || 0,
+      Number(array![2]) || 0,
+      Number(array![3]) || 0,
+      Number(array![4]) || 0,
+    ];
+  };
+
+  const nodeUpdateFilter = (node: Konva.Node) => {
+    node.cache();
+    const rgba = getRGBANum(shopData.value.bgColor);
+    node.red(rgba[0]);
+    node.green(rgba[1]);
+    node.blue(rgba[2]);
+    node.alpha(rgba[3]);
+  };
+
+  const getPointCurvConfig = () => {
+    return {
+      x: 0,
+      y: 0,
+      width: 32,
+      height: 39,
+      // fill: shopData.value.bgColor,
+      image: curvImage.value,
+    };
+  };
+
+  const getRectCurConfig = () => {
+    return {
+      x: 53,
+      y: 0,
+      width: 160,
+      height: 38,
+      // fill: shopData.value.bgColor,
+      image: rectImage.value,
+    };
+  };
+
+  const getTextConfig = () => {
+    return {
+      x: 53,
+      y: 0,
+      text: shopData.value.name,
+      fontSize: shopData.value.fontSize,
+      fontFamily: 'TRENDS',
+      fill: shopData.value.fontColor,
+      width: 160,
+      height: 32,
+      align: 'center',
+      verticalAlign: 'middle',
+    };
+  };
+
+  const shineConfig = computed(() => {
+    return {
+      x: 0,
+      y: 0,
+      width: 213,
+      height: 38,
+      // fill: shopData.value.bgColor,
+      image: shineImage.value,
+    };
+  });
+
+  watch(
+    shopData.value,
+    () => {
+      console.log('pointRef.value!.getNode()', pointRef.value!.getNode());
+      nextTick(() => {
+        console.log('pointRef.value!.getNode()', pointRef.value!.getNode());
+        nodeUpdateFilter(pointRef.value!.getNode());
+
+        nodeUpdateFilter(rectRef.value!.getNode());
+      });
+    },
+    { deep: true },
+  );
+
+  onMounted(() => {
+    const svgImg = new Image();
+    svgImg.onload = () => {
+      curvImage.value = svgImg;
+      nextTick(() => {
+        nodeUpdateFilter(pointRef.value?.getNode());
+      });
+    };
+    svgImg.src = pointCurv;
+
+    const rectImg = new Image();
+    rectImg.onload = () => {
+      rectImage.value = rectImg;
+      nextTick(() => {
+        nodeUpdateFilter(rectRef.value?.getNode());
+      });
+    };
+    rectImg.src = rectBlock;
+
+    const shineImg = new Image();
+    shineImg.onload = () => {
+      shineImage.value = shineImg;
+    };
+    shineImg.src = shine;
+
+    rectRef.value?.getNode().filters([Konva.Filters.RGBA]);
+    pointRef.value?.getNode().filters([Konva.Filters.RGBA]);
+  });
+</script>
+
+<style scoped></style>

+ 6 - 0
src/views/page-config/component/mapContainer/LabelItem.vue

@@ -50,6 +50,7 @@
       y: 0,
       width: 32,
       height: 39,
+      // fill: shopData.value.bgColor,
       image: curvImage.value,
     };
   };
@@ -60,6 +61,7 @@
       y: 0,
       width: 160,
       height: 38,
+      // fill: shopData.value.bgColor,
       image: rectImage.value,
     };
   };
@@ -85,6 +87,7 @@
       y: 0,
       width: 213,
       height: 38,
+      // fill: shopData.value.bgColor,
       image: shineImage.value,
     };
   });
@@ -92,8 +95,11 @@
   watch(
     shopData.value,
     () => {
+      console.log('pointRef.value!.getNode()', pointRef.value!.getNode());
       nextTick(() => {
+        console.log('pointRef.value!.getNode()', pointRef.value!.getNode());
         nodeUpdateFilter(pointRef.value!.getNode());
+
         nodeUpdateFilter(rectRef.value!.getNode());
       });
     },

+ 114 - 0
src/views/page-config/component/mapContainer/MapContainer copy.vue

@@ -0,0 +1,114 @@
+<template>
+  <div>
+    <v-stage
+      ref="stageRef"
+      :config="stageSize"
+      @mousedown="handleStageMouseDown"
+      @touchstart="handleStageMouseDown"
+    >
+      <v-layer ref="layerRef">
+        <v-image :config="bgConfig" />
+        <v-group
+          v-for="item in showShops"
+          :key="item.id"
+          :config="getGroupConfig(item)"
+          @transformend="handleTransformEnd"
+        >
+          <LabelItem :shop="item" />
+        </v-group>
+        <v-transformer ref="transformerRef" :config="transformerConfig" />
+      </v-layer>
+    </v-stage>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { computed, ref } from 'vue';
+  import LabelItem from './LabelItem.vue';
+  import { storeToRefs } from 'pinia';
+  import useMapEditor, { MapWorkShopInfoItem } from '../../stores/useMapEditor';
+  import Konva from 'konva';
+
+  const mapEditor = useMapEditor();
+  const { mapWidth, mapHeight, showShops, bgImage } = storeToRefs(mapEditor);
+
+  const stageRef = ref<Konva.Stage>();
+  const layerRef = ref<Konva.Layer>();
+  const transformerRef = ref<Konva.Transformer>();
+
+  let selectedShape = -1;
+
+  const stageSize = computed(() => {
+    return {
+      // width: mapWidth.value,
+      // height: mapHeight.value,
+      width: 1920,
+      height: 1080,
+    };
+  });
+
+  const bgConfig = computed(() => {
+    return {
+      width: 1920,
+      height: 1080,
+      image: bgImage.value,
+      name: 'bg',
+    };
+  });
+
+  const getGroupConfig = (shop: MapWorkShopInfoItem) => {
+    return {
+      x: shop.x,
+      y: shop.y,
+      id: shop.id + '',
+      draggable: true,
+      name: 'group',
+    };
+  };
+
+  const transformerConfig = {
+    keepRatio: true,
+    rotateEnabled: false,
+    enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
+  };
+
+  const handleStageMouseDown = (e) => {
+    if (e.target.attrs.name === 'bg') {
+      selectedShape = -1;
+      updateTransformer();
+    }
+
+    if (e.target.parent.attrs.name === 'group') {
+      if (e.target.parent.id() === selectedShape) {
+        return;
+      }
+      selectedShape = e.target.parent.id();
+
+      updateTransformer();
+    }
+  };
+
+  const handleTransformEnd = (e) => {};
+
+  const updateTransformer = () => {
+    const transformerNode = transformerRef.value!.getNode();
+    const layer = layerRef.value!.getNode().getLayer();
+
+    if (selectedShape >= 0) {
+      const selectedNode = layer.findOne('#' + selectedShape);
+      (transformerNode as Konva.Transformer).nodes([selectedNode!]);
+    } else {
+      (transformerNode as Konva.Transformer).nodes([]);
+    }
+  };
+
+  const getLayout = () => {
+    const json = stageRef.value?.getStage().toJSON();
+
+    return json;
+  };
+
+  defineExpose({ getLayout });
+</script>
+
+<style scoped></style>

+ 124 - 0
src/views/page-config/stores/useMapEditor copy 2.ts

@@ -0,0 +1,124 @@
+import { ref } from 'vue';
+import { defineStore } from 'pinia';
+import { WorkShopInfoItem } from '@/api/scene/scene';
+import { cloneDeep } from 'lodash-es';
+import { useGlobSetting } from '@/hooks/setting';
+import safeParse from '@/utils/safeParse';
+import urlJoin from 'url-join';
+import emptyImg from '@/assets/images/table/table-empty.png';
+
+export enum LabelPositionEnum {
+  LEFT = 'left',
+  RIGHT = 'right',
+  TOP = 'top',
+}
+
+export type EditStyle = {
+  x: number;
+  y: number;
+  scale: number;
+  thumbnail?: string;
+  bgColor: string;
+  fontSize: number;
+  fontColor: string;
+  posType: LabelPositionEnum;
+};
+
+export type MapWorkShopInfoItem = WorkShopInfoItem & EditStyle;
+
+export const useMapEditor = defineStore('home-map-ediotr', () => {
+  const globSetting = useGlobSetting();
+
+  const bgImg = ref('');
+  const mapWidth = ref(0);
+  const mapHeight = ref(0);
+  const addedShops = ref<MapWorkShopInfoItem[]>([]);
+  const showShops = ref<MapWorkShopInfoItem[]>([]);
+  const activeShopId = ref<number>();
+
+  /** konva elements refs */
+  const bgImage = ref<HTMLImageElement>(new Image());
+
+  const addBg = () => {
+    const imgUrl = urlJoin(globSetting.imgUrl!, bgImg.value);
+    console.log(imgUrl);
+
+    const tempImg = new Image();
+    tempImg.onload = () => {
+      mapWidth.value = tempImg.width;
+      mapHeight.value = tempImg.height;
+      bgImage.value = tempImg;
+    };
+    tempImg.src = imgUrl;
+  };
+
+  const addShop = (shop: MapWorkShopInfoItem) => {
+    activeShopId.value = shop.id;
+    addedShops.value.push(cloneDeep(shop));
+    showShops.value.push(cloneDeep(shop));
+  };
+
+  const calcLayout = (json: string) => {
+    const mapJson = safeParse(json);
+    const mapData = mapJson.children[0].children;
+    const layout = {
+      bgInfo: {
+        width: mapWidth.value,
+        height: mapHeight.value,
+        img: bgImg.value,
+      },
+      shopList: addedShops.value.map((shop) => {
+        const mapAttr = mapData.find((item) => item.id === shop.id + '')!.attrs;
+        const temp = cloneDeep(shop) as any;
+        delete temp.children;
+        temp.x = mapAttr.x;
+        temp.y = mapAttr.y;
+        temp.scale = mapAttr.scaleX || 1;
+        return temp;
+      }),
+    };
+
+    return JSON.stringify(layout);
+  };
+
+  const createMap = (layout) => {
+    bgImg.value = layout.bgInfo.img;
+    mapWidth.value = layout.bgInfo.width;
+    mapHeight.value = layout.bgInfo.height;
+    addedShops.value = cloneDeep(layout.shopList);
+    showShops.value = cloneDeep(layout.shopList);
+  };
+
+  const deleteShop = () => {
+    addedShops.value = addedShops.value.filter((item) => item.id !== activeShopId.value);
+    showShops.value = showShops.value.filter((item) => item.id !== activeShopId.value);
+    activeShopId.value = undefined;
+  };
+
+  const resetMap = () => {
+    bgImg.value = '';
+    mapWidth.value = 0;
+    mapHeight.value = 0;
+    addedShops.value = [];
+    showShops.value = [];
+    activeShopId.value = undefined;
+  };
+
+  return {
+    bgImg,
+    mapWidth,
+    mapHeight,
+    addedShops,
+    showShops,
+    activeShopId,
+    bgImage,
+    addShop,
+    addBg,
+    calcLayout,
+    createMap,
+    deleteShop,
+    resetMap,
+  };
+});
+
+export default useMapEditor;

+ 1 - 0
src/views/page-config/stores/useMapEditor.ts

@@ -56,6 +56,7 @@ export const useMapEditor = defineStore('home-map-ediotr', () => {
     activeShopId.value = shop.id;
     addedShops.value.push(cloneDeep(shop));
     showShops.value.push(cloneDeep(shop));
+    console.log('showShops.value', showShops.value);
   };
 
   const calcLayout = (json: string) => {