<template>
  <div
    class="outer-container"
    :class="{ editMode: data.isEditing }"
    :style="gridItemStyle"
  >
    <div class="items-container">
      <div class="grid-items-wrapper">
        <transition-group name="grid-fade" tag="div" class="grid-inner-wrapper">
          <div
            v-for="(item, index) in data.list"
            :key="item.itemView.id"
            class="grid-item"
            :class="{
              'being-dragged': draggingIndex === index,
              hidden: isDragClone && draggingIndex === index,
              'hover-target': hoverIndex === index && draggingIndex !== index,
              'disabled-item': item.itemView.enable === false,
            }"
            :style="{
              overflow: data.isEditing ? 'visible' : 'hidden',
            }"
            :data-index="index"
            @touchstart="(event) => startLongPress(event, index)"
            @touchmove="checkLongPressMove"
            @touchend="endTouch"
            @touchcancel="endTouch"
          >
            <div
              v-if="hasAnimation(item, 'bgAnimView')"
              class="lottie-container bg-anim"
              :style="applyNormalAttribute(item.bgAnimView, 'bgAnimView')"
              :ref="`bgAnim-${item.itemView.id}`"
            ></div>
            <div
              v-if="hasAnimation(item, 'frontAnimView')"
              class="lottie-container front-anim"
              :style="applyNormalAttribute(item.frontAnimView, 'frontAnimView')"
              :ref="`frontAnim-${item.itemView.id}`"
            ></div>
            <div
              :style="applyNormalAttribute(item.itemView, 'itemView')"
              class="grid-box"
              :class="{ shaking: data.isEditing }"
              @click.stop.prevent="(e) => itemViewClick(e, item, index)"
            >
              <div class="flexBox">
                <img
                  :src="getUrl(item, 'iconImage')"
                  :style="applyNormalAttribute(item.iconImage, 'iconImage')"
                />
                <div>
                  <div @click.stop.prevent v-if="!data.isEditing">
                    <button
                      class="actionButton"
                      @click.stop.prevent="(e) => actionClick(e, item, index)"
                      :style="applyNormalAttribute(item.actionButton, 'actionButton')"
                    >
                      {{ getText(item, 'actionButton') }}
                    </button>
                    <div
                      v-if="getUrl(item, 'loadingAnimView', 'animUrl')"
                      class="loading-anim"
                      :style="applyNormalAttribute(item.loadingAnimView, 'loadingAnimView')"
                      :ref="`loadingAnim-${item.itemView.id}`"
                    ></div>
                  </div>
                  <div @click.stop.prevent v-if="!data.isEditing">
                    <img
                      :src="getUrl(item, 'rightIcon')"
                      :style="applyNormalAttribute(item.rightIcon, 'rightIcon')"
                      @click.stop.prevent="(e) => rightIconClick(e)"
                    />
                  </div>
                  <div @click.stop.prevent v-if="!data.isEditing">
                    <img
                      class="leftTopIcon"
                      :src="getUrl(item, 'leftTopIcon')"
                      :style="applyNormalAttribute(item.leftTopIcon, 'leftTopIcon')"
                      @click.stop.prevent
                    />
                  </div>
                  <div @click.stop.prevent v-if="data.isEditing">
                    <img
                      class="isSelected"
                      @click.stop.prevent="
                        (e) => selectIconClick(e, item, index)
                      "
                      :src="
                        item.itemView.isSelected
                          ? getUrl(item, 'selectIcon', 'selectedUrl')
                          : getUrl(item, 'selectIcon')
                      "
                      :style="applyNormalAttribute(item.selectIcon, 'selectIcon')"
                    />
                  </div>
                </div>
              </div>
              <div class="itemText" :style="[applyNormalAttribute(item.text, 'text')]">
                {{ getText(item, 'text') }}
              </div>
            </div>
          </div>
        </transition-group>
      </div>
    </div>

    <!-- 拖拽克隆元素将通过JavaScript动态创建并挂载到body --> 
  </div>
</template>

<script>
import lottie from 'lottie-web';
const scla = 2;

// 常量配置
const REQUIRED_TYPES = [
  'itemView',
  'text', 
  'actionButton',
  'rightIcon',
  'leftTopIcon',
  'iconImage',
  'selectIcon',
  'loadingAnimView',
  'bgAnimView',
  'frontAnimView',
];

const ANIMATION_TYPES = [
  { type: 'bg', view: 'bgAnimView' },
  { type: 'loading', view: 'loadingAnimView' },
  { type: 'front', view: 'frontAnimView' }
];

export default {
  name: 'EditableGrid',
  props: {
    data: {
      type: Object,
      default: () => ({}),
    },
    onClickRightIcon: { type: Function, default: () => {} },
    onClickActionButton: { type: Function, default: () => {} },
    onEditStateChanged: { type: Function, default: () => {} },
    onClickItem: { type: Function, default: () => {} },
    onSelectItems: { type: Function, default: () => {} },
    onDragEventStart: { type: Function, default: () => {} },
    onDragEventEnd: { type: Function, default: () => {} },
  },
  data() {
    return {
      targetTouchX: 0,
      targetTouchY: 0,
      selected: null,
      longPressTimer: null,
      longPressDuration: 350,
      draggingIndex: null,
      hoverIndex: null,
      isTouchDragging: false,
      lastSwapTime: 0,
      isAnimating: false,
      lastSwapPair: null, // 记录上次交换的元素对
      stablePositionTime: 0, // 稳定位置时间
      lastTouchX: 0, // 上次触摸X坐标
      lastTouchY: 0, // 上次触摸Y坐标
      touchStartX: 0,
      touchStartY: 0,
      draggedItemRect: null,
      isDragClone: false,
      dragCloneX: 0,
      dragCloneY: 0,
      touchOffsetX: 0,
      touchOffsetY: 0,
      gridBoxWidth: 0,
      lottieAnimations: {},
      isScrolling: false,
      scrollThreshold: 5,
      fixedItemWidth: 0,
      fixedItemHeight: 0,
      animationFrameId: null,
      dragCloneElement: null, // 拖拽克隆DOM元素
      // 性能优化缓存
      gridItemsCache: [],
      lastCacheTime: 0,
      cacheValidDuration: 1000, // 缓存有效期1秒
      listChangeDebounced: null,
      updatePositionThrottled: null,
      // 避免频繁DOM查询
      containerElement: null,
      isUpdatingPosition: false,
    };
  },
  computed: {
    gridItemStyle() {
      return {
        '--grid-cols': this.data.spanCount || this.cols,
        '--grid-gap': `${this.data.spaceSize || 8}px`,
        '--grid-margin': `${
          this.data.layoutConfig.marginStart + this.data.layoutConfig.marginEnd
        }px`,
        marginTop: this.data.layoutConfig.marginTop * scla,
        marginBottom: this.data.layoutConfig.marginBottom * scla,
        marginLeft: this.data.layoutConfig.marginStart * scla,
        marginRight: this.data.layoutConfig.marginEnd * scla,
      };
    },
  },
  methods: {
    // 添加工具方法
    isNil(value) {
      return value === null || value === undefined;
    },

    // 获取属性值，支持回退到全局数据和默认值
    getValue(itemData, globalData, property, defaultValue = null) {
      // 安全地获取属性值，避免访问undefined对象的属性
      let itemValue;
      let globalValue;
      
      try {
        itemValue = itemData && typeof itemData === 'object' ? itemData[property] : undefined;
      } catch (e) {
        itemValue = undefined;
      }
      
      try {
        globalValue = globalData && typeof globalData === 'object' ? globalData[property] : undefined;
      } catch (e) {
        globalValue = undefined;
      }
      
      if (!this.isNil(itemValue)) {
        return itemValue;
      }
      if (!this.isNil(globalValue)) {
        return globalValue;
      }
      return defaultValue;
    },

    // 简化的URL获取方法
    getUrl(item, type, property = 'url') {
      return this.getValue(item[type], this.data.globalData[type], property, '');
    },

    // 简化的文本获取方法  
    getText(item, type, property = 'text') {
      return this.getValue(item[type], this.data.globalData[type], property, '');
    },

    // 简化的动画URL检查方法
    hasAnimation(item, type) {
      return this.getValue(item[type], this.data.globalData[type], 'animUrl', '') && !this.data.isEditing;
    },

    // 性能优化工具方法
    debounce(func, wait) {
      let timeout;
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeout);
          func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    },

    throttle(func, limit) {
      let inThrottle;
      return function executedFunction(...args) {
        if (!inThrottle) {
          func.apply(this, args);
          inThrottle = true;
          setTimeout(() => inThrottle = false, limit);
        }
      };
    },

    // 缓存DOM查询结果
    getCachedGridItems() {
      const now = Date.now();
      if (now - this.lastCacheTime > this.cacheValidDuration || this.gridItemsCache.length === 0) {
        this.gridItemsCache = Array.from(document.querySelectorAll('.grid-item'));
        this.lastCacheTime = now;
      }
      return this.gridItemsCache;
    },

    // 清除DOM缓存
    clearGridItemsCache() {
      this.gridItemsCache = [];
      this.lastCacheTime = 0;
    },

    // 优化的位置更新方法
    optimizedUpdateDragPosition() {
      if (this.isUpdatingPosition) return;
      
      this.isUpdatingPosition = true;
      
      const easing = 0.6;
      
      // 获取outer-container的边界
      const containerRect = this.containerElement.getBoundingClientRect();
      
      // 计算相对于容器的目标位置
      let targetX = this.targetTouchX - this.touchOffsetX - containerRect.left;
      let targetY = this.targetTouchY - this.touchOffsetY - containerRect.top;
      
      // 限制拖拽范围在容器内
      const cloneWidth = this.fixedItemWidth;
      const cloneHeight = this.fixedItemHeight;
      const maxX = containerRect.width - cloneWidth;
      const maxY = containerRect.height - cloneHeight;
      
      // 限制X坐标
      targetX = Math.max(0, Math.min(targetX, maxX));
      
      // 限制Y坐标
      targetY = Math.max(0, Math.min(targetY, maxY));
      
      this.dragCloneX += (targetX - this.dragCloneX) * easing;
      this.dragCloneY += (targetY - this.dragCloneY) * easing;
      
      if (Math.abs(this.dragCloneX - targetX) < 0.5) {
        this.dragCloneX = targetX;
      }
      if (Math.abs(this.dragCloneY - targetY) < 0.5) {
        this.dragCloneY = targetY;
      }
      
      this.updateDragClonePosition();
      
      this.isUpdatingPosition = false;
      
      if (this.isTouchDragging) {
        this.animationFrameId = requestAnimationFrame(() => this.optimizedUpdateDragPosition());
      }
    },

    // 批量更新样式，减少重绘
    batchUpdateStyles(elements, styles) {
      if (!elements || elements.length === 0) return;
      
      // 使用documentFragment来减少DOM操作
      elements.forEach(element => {
        Object.keys(styles).forEach(property => {
          element.style[property] = styles[property];
        });
      });
    },

    // 确保项目数据结构完整性
    ensureItemStructure(item) {
      REQUIRED_TYPES.forEach((type) => {
        if (!item[type] || typeof item[type] !== 'object') {
          item[type] = {};
        }
      });

      return item;
    },

    // 抽取的动画初始化公共方法
    initItemAnimations(item, itemData = null) {
      const itemId = String(item.itemView.id);
      const dataSource = itemData || item; // 支持传入不同的数据源
      
      ANIMATION_TYPES.forEach(({ type, view }) => {
        const animUrl = this.getValue(
          dataSource[view], 
          this.data.globalData[view], 
          'animUrl', 
          ''
        );
        if (animUrl) {
          this.createLottieAnimation(type, itemId, dataSource[view], dataSource);
        }
      });
    },

    // 统一的样式应用方法，支持缩放控制
    applyOptimizedAttribute(itemData = {}, type = '', useScale = true) {
      const globalData = this.data.globalData[type] || {};
      const scale = useScale ? scla : 1; // 根据参数决定是否应用缩放
      
      const style = {
        color: this.getValue(itemData, globalData, 'textColor', '#000000'),
        fontWeight: this.getValue(itemData, globalData, 'fontWeight', 'normal'),
        fontFamily: this.getValue(itemData, globalData, 'fontFamilyPath', 'inherit'),
        fontSize: `${(this.getValue(itemData, globalData, 'textSize', 16)) * scale}px`,
        // 布局相关样式
        backgroundColor: this.getValue(itemData, globalData, 'backgroundColor', 'transparent'),
        borderRadius: `${(this.getValue(itemData, globalData, 'cornerRadius', 0)) * scale}px`,
        opacity: this.getValue(itemData, globalData, 'alpha', 1),
      };

      // 处理width
      const width = this.getValue(itemData, globalData, 'width');
      if (typeof width === 'number' && width > 0) {
        style.width = `${width * scale}px`;
      } else if (width === -1) {
        style.width = '100%';
      } else if (width && typeof width === 'string') {
        style.width = width;
      }

      // 处理height
      const height = this.getValue(itemData, globalData, 'height');
      if (typeof height === 'number' && height > 0) {
        style.height = `${height * scale}px`;
      } else if (height && typeof height === 'string') {
        style.height = height;
      }

      // 处理visibility和display
      const visibility = this.getValue(itemData, globalData, 'visibility');
      if (typeof visibility === 'number') {
        if (visibility === 0) {
          style.display = 'none';
        } else {
          style.display = this.getValue(itemData, globalData, 'display', '');
          style.visibility = visibility === 1 ? 'visible' : 'hidden';
        }
      } else {
        style.display = this.getValue(itemData, globalData, 'display', '');
      }

      // 处理边框
      const borderColor = this.data.isEditing
        ? this.getValue(itemData, globalData, 'selectedBorderColor', '')
        : this.getValue(itemData, globalData, 'normalBorderColor', '');
      const borderWidth = this.data.isEditing
        ? this.getValue(itemData, globalData, 'selectedBorderWidth', 0)
        : this.getValue(itemData, globalData, 'normalBorderWidth', 0);
      
      style.borderColor = borderColor;
      style.borderWidth = `${borderWidth * scale}px`;

      // 处理padding
      const padding = this.getValue(itemData, globalData, 'padding');
      if (padding && Array.isArray(padding)) {
        style.paddingTop = `${(padding[1] || 0) * scale}px`;
        style.paddingLeft = `${(padding[0] || 0) * scale}px`;
        style.paddingBottom = `${(padding[3] || 0) * scale}px`;
        style.paddingRight = `${(padding[2] || 0) * scale}px`;
      }

      // 处理margin
      const margin = this.getValue(itemData, globalData, 'margin');
      if (margin && Array.isArray(margin)) {
        style.marginTop = `${(margin[1] || 0) * scale}px`;
        style.marginLeft = `${(margin[0] || 0) * scale}px`;
        style.marginBottom = `${(margin[3] || 0) * scale}px`;
        style.marginRight = `${(margin[2] || 0) * scale}px`;
      }

      return style;
    },





    // 优化内存使用
    optimizeMemoryUsage() {
      // 清理无用的动画实例
      Object.keys(this.lottieAnimations).forEach(key => {
        const anim = this.lottieAnimations[key];
        if (anim && anim.isLoaded === false) {
          anim.destroy();
          delete this.lottieAnimations[key];
        }
      });
      
      // 清理DOM缓存
      if (this.gridItemsCache.length > 50) { // 如果缓存过多，清理
        this.clearGridItemsCache();
      }
    },

    // 获取元素在页面中的绝对位置（考虑所有transform影响）
    getAbsolutePosition(element) {
      let x = 0;
      let y = 0;
      let currentElement = element;
      
      while (currentElement) {
        const rect = currentElement.getBoundingClientRect();
        if (currentElement === element) {
          x += rect.left;
          y += rect.top;
        }
        currentElement = currentElement.offsetParent;
      }
      
      // 加上页面滚动偏移
      x += window.pageXOffset;
      y += window.pageYOffset;
      
      return { x, y };
    },

    // 创建拖拽克隆元素
    createDragClone(index) {
      if (this.dragCloneElement) {
        this.destroyDragClone();
      }

      const item = this.data.list[index];
      if (!item) return;

      // 创建拖拽容器
      this.dragCloneElement = document.createElement('div');
      this.dragCloneElement.className = 'drag-clone-dynamic';
      
      // 设置基本样式（使用不带缩放的样式方法）
      const itemViewStyle = this.applyOptimizedAttribute(item.itemView, 'itemView', false);
      Object.assign(this.dragCloneElement.style, {
        position: 'absolute',
        zIndex: '9999',
        userSelect: 'none',
        boxSizing: 'border-box',
        flexDirection: 'column',
        pointerEvents: 'none',
        transition: 'none',
        willChange: 'transform',
        left: '0',
        top: '0',
        // 覆盖itemViewStyle中可能的宽高设置，确保使用固定尺寸
        ...itemViewStyle,
        width: `${this.fixedItemWidth}px`,
        height: `${this.fixedItemHeight}px`,
        display: 'flex',
        justifyContent: 'space-between',
      });

      // 创建内容HTML（不使用缩放）
      const iconImageStyle = this.applyOptimizedAttribute(item.iconImage, 'iconImage', false);
      const selectIconStyle = this.applyOptimizedAttribute(item.selectIcon, 'selectIcon', false);
      const textStyle = this.applyOptimizedAttribute(item.text, 'text', false);
      const actionButtonStyle = this.applyOptimizedAttribute(item.actionButton, 'actionButton', false);
      
      // 将样式对象转换为CSS字符串
      const stylesToString = (styleObj) => {
        return Object.entries(styleObj)
          .map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${value}`)
          .join('; ');
      };

      // 确保内部grid-box也使用固定尺寸（使用不带缩放的样式方法）
      const gridBoxStyle = {
        ...this.applyOptimizedAttribute(item.itemView, 'itemView', false),
        width: `${this.fixedItemWidth}px`,
        height: `${this.fixedItemHeight}px`
      };

      this.dragCloneElement.innerHTML = `
        <div class="grid-box" style="${stylesToString(gridBoxStyle)} ;display: flex; justify-content: space-between;flex-direction: column">
          <div class="flexBox" style="display: flex; justify-content: space-between; width: 100%; position: relative; flex-direction: row;">
            <img src="${this.getUrl(item, 'iconImage')}" style="${stylesToString(iconImageStyle)}" />
            <div style="pointer-events: none;">
              <img 
                class="isSelected" 
                src="${item.itemView.isSelected 
                  ? this.getUrl(item, 'selectIcon', 'selectedUrl')
                  : this.getUrl(item, 'selectIcon')}"
                style="${stylesToString(selectIconStyle)}"
              />
            </div>
          </div>
          <div class="itemText" style="${stylesToString(textStyle)}; display: block; width: 80%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
            ${this.getText(item, 'text')}
          </div>
        </div>
      `;

      // 挂载到outer-container而不是body，这样可以更好地控制拖拽范围
      this.containerElement.appendChild(this.dragCloneElement);
      
      return this.dragCloneElement;
    },

    // 销毁拖拽克隆元素
    destroyDragClone() {
      if (this.dragCloneElement) {
        if (this.dragCloneElement.parentNode) {
          this.dragCloneElement.parentNode.removeChild(this.dragCloneElement);
        }
        this.dragCloneElement = null;
      }
    },

    // 更新拖拽克隆元素位置
    updateDragClonePosition() {
      if (!this.dragCloneElement) return;
      
      this.dragCloneElement.style.transform = `translate(${this.dragCloneX}px, ${this.dragCloneY}px)`;
    },

    // 普通渲染的样式应用方法（使用缩放）
    applyNormalAttribute(itemData = {}, type = '') {
      return this.applyOptimizedAttribute(itemData, type, true);
    },
    updateListItem(data) {
      const id = data.itemView.id;
      const index = this.data.list.findIndex((item) => item.itemView.id == id);

      if (index === -1) {
        return;
      }

      // 确保数据结构完整性
      this.ensureItemStructure(data);

      // 直接更新数据，不再需要合并
      this.$set(this.data.list, index, data);
      this.$nextTick(() => {
        const itemId = String(data.itemView.id);
        
        // 使用抽取的公共方法初始化动画
        this.initItemAnimations(data, data);
      });
    },
    createLottieAnimation(type, itemId, animView, itemData) {
      const animKey = `${type}-${itemId}`;
      const refName = `${type}Anim-${itemId}`;

      // 检查DOM元素是否存在
      const animEl = this.$refs[refName];
      if (!animEl || !animEl[0] || !animView.animUrl) {
        return;
      }

      // 检查可见性
      if (
        typeof animView.visibility === 'number' &&
        animView.visibility === 0
      ) {
        return;
      }

      // 如果是bg或front动画，需要检查并清理另一个
      if (type === 'bg' || type === 'front') {
        const otherType = type === 'bg' ? 'front' : 'bg';
        const otherAnimKey = `${otherType}-${itemId}`;

        // 如果另一个动画正在运行，先销毁它
        if (this.lottieAnimations[otherAnimKey]) {
          this.lottieAnimations[otherAnimKey].destroy();
          delete this.lottieAnimations[otherAnimKey];

          // 清空对应的animUrl数据
          const index = this.data.list.findIndex(
            (i) => i.itemView.id == itemId
          );
          if (index !== -1) {
            this.$set(
              this.data.list[index][`${otherType}AnimView`],
              'animUrl',
              ''
            );
          }
        }
      }

      // 销毁当前类型的旧动画
      if (this.lottieAnimations[animKey]) {
        this.lottieAnimations[animKey].destroy();
        delete this.lottieAnimations[animKey];
      }

      try {
        const anim = lottie.loadAnimation({
          container: animEl[0],
          renderer: 'svg',
          loop: Boolean(itemData.animRepeatCount) || false,
          autoplay: true,
          path: animView.animUrl,
          rendererSettings: {
            preserveAspectRatio: 'xMidYMid slice',
            progressiveLoad: true,
            hideOnTransparent: true,
          },
        });

        this.lottieAnimations[animKey] = anim;

        // 非循环动画完成后清理
        if (!itemData.animRepeatCount) {
          anim.addEventListener('complete', () => {
            if (this.lottieAnimations[animKey] === anim) {
              anim.destroy();
              delete this.lottieAnimations[animKey];

              // 清空对应的animUrl数据
              const index = this.data.list.findIndex(
                (i) => i.itemView.id == itemId
              );
              if (index !== -1) {
                this.$set(
                  this.data.list[index][`${type}AnimView`],
                  'animUrl',
                  ''
                );
              }
            }
          });
        }
      } catch (error) {
        console.error(`创建${type}动画失败:`, error);
      }
    },
    getListData(callback) {
      let data = Array.from(this.data.list);
      data = data.map((item) => {
        // 确保每个项目都有完整的数据结构
        const completeItem = { ...item };
        this.ensureItemStructure(completeItem);
        
        // 为了外部使用，合并全局数据到每个类型
        REQUIRED_TYPES.forEach((type) => {
          const globalData = this.data.globalData && this.data.globalData[type] || {};
          completeItem[type] = {
            ...globalData,
            ...completeItem[type]
          };
        });
        
        return {
          ...completeItem,
          itemView: {
            ...completeItem.itemView,
            id: String(completeItem.itemView.id),
          },
        };
      });
      callback({ listData: data });
    },
    rightIconClick(e) {
      e.preventDefault();
      e.stopPropagation();
      this.$emit('onClickRightIcon', e);
      return false;
    },
    onSelectItems() {
      const selectedIds = this.data.list
        .filter((item) => item.itemView.isSelected)
        .map((item) => String(item.itemView.id));
      return selectedIds;
    },
    selectIconClick(e, item, index) {
      if (item.selectIcon.visibility) {
        item.itemView.isSelected = !item.itemView.isSelected;
      }
      e && e.preventDefault();
      e && e.stopPropagation();
      const target = {
        ...item.itemView,
        id: String(item.itemView.id),
        index,
        ...e,
      };
      this.$emit('onClickSelectIcon', target);
      this.$emit('onSelectItems', target);
      return false;
    },

    itemViewClick(e, item, index) {
      if (this.isTouchDragging || this.longPressTimer === null && this.data.isEditing) {
        return;
      }

      if (this.data.isEditing) {
        if (item.selectIcon.visibility) {
          item.itemView.isSelected = !item.itemView.isSelected;
        }
      }

      // 确保取消任何长按计时器
      this.cancelLongPress();

      e.preventDefault();
      e.stopPropagation();
      const target = {
        ...item.itemView,
        id: String(item.itemView.id),
        index,
        ...e,
      };
      this.$emit('onClickItem', target);
      this.$emit('onSelectItems', target);
    },

    actionClick(e, item, index) {
      e.preventDefault();
      e.stopPropagation(); // 阻止事件冒泡到itemViewClick

      // 在触发事件前，先清理所有其他项目的动画实例
      this.cleanupOtherAnimations(item.itemView.id);

      const target = {
        ...item.itemView,
        id: String(item.itemView.id),
        index,
        ...e,
      };
      this.$emit('onClickActionButton', target);
      return false;
    },

    cleanupOtherAnimations(currentItemId) {
      Object.keys(this.lottieAnimations).forEach((key) => {
        if (!key.includes(`-${currentItemId}`)) {
          if (this.lottieAnimations[key]) {
            const anim = this.lottieAnimations[key];

            // 不要立即销毁，而是先停止动画
            anim.pause();

            // 使用 setTimeout 延迟销毁，给新动画一个启动的时间
            setTimeout(() => {
              try {
                if (this.lottieAnimations[key] === anim) {
                  anim.removeEventListener('complete');
                  anim.destroy();
                  delete this.lottieAnimations[key];

                  // 提取项目ID和动画类型
                  const parts = key.split('-');
                  if (parts.length === 2) {
                    const animType = parts[0];
                    const itemId = parts[1];

                    // 延迟隐藏对应的动画容器
                    this.$nextTick(() => {
                      const refName = `${animType}Anim-${itemId}`;
                      const animContainer =
                        this.$refs[refName] && this.$refs[refName][0];
                      if (animContainer) {
                        // 使用 opacity 过渡而不是直接设置 display: none
                        animContainer.style.opacity = '0';
                        animContainer.style.transition = 'opacity 0.2s';
                        setTimeout(() => {
                          animContainer.style.display = 'none';
                        }, 200);
                      }
                    });
                  }
                }
              } catch (e) {
                console.warn(`清理动画失败: ${e.message}`);
              }
            }, 50);
          }
        }
      });
    },





    // 开始长按
    startLongPress(e, index) {
      if (!this.data.isEditable) {
        return;
      }
      this.$emit('onDragEventStart', e);
      // 只在编辑模式下阻止事件冒泡和默认行为
      this.cancelLongPress();
      // 记录起始触摸位置和索引
      const touch = e.changedTouches[0];
      this.touchStartX = touch.pageX;
      this.touchStartY = touch.pageY;
      this.isScrolling = false; // 重置滚动状态

      // 设置新的长按计时器
      this.longPressTimer = setTimeout(() => {
        // 只有在没有滚动的情况下才激活拖拽模式
        if (!this.isScrolling) {
          this.activateDragMode(index);
        }
      }, this.longPressDuration);
    },

    // 检查长按过程中的移动
    checkLongPressMove(e) {
      if (this.data.isEditing) {
        e.oriEvent.stopImmediatePropagation();
      }
      if (!this.data.isEditable) {
        return;
      }

      const touch = e.changedTouches[0];
      const moveX = Math.abs(touch.pageX - this.touchStartX);
      const moveY = Math.abs(touch.pageY - this.touchStartY);

      // 如果水平移动大于垂直移动，则阻止事件传播
      if (moveX > moveY && !this.isTouchDragging && this.data.isEditing) {
        if (e.oriEvent) {
          e.oriEvent.preventDefault();
          e.oriEvent.stopPropagation();
          e.oriEvent.stopImmediatePropagation();
        }
      }

      // 如果已经在拖拽模式，交给onTouchMove处理
      if (this.isTouchDragging) {
        this.onTouchMove(e);
        return;
      }

      // 检测是否在滚动
      if (moveY > this.scrollThreshold * 3) {
        // 增加滚动阈值以更容易识别滚动意图
        this.isScrolling = true;
        this.cancelLongPress();
        return;
      }

      // 如果移动超过阈值，取消长按
      if (moveX > this.scrollThreshold || moveY > this.scrollThreshold) {
        this.cancelLongPress();
      }

      return false;
    },

    // 激活拖拽模式
    activateDragMode(index) {
      if (this.data.isEditing) {
        // 重置交换状态
        this.lastSwapPair = null;
        this.stablePositionTime = 0;
        this.isAnimating = false;
        this.lastTouchX = this.touchStartX;
        this.lastTouchY = this.touchStartY;
        
        // 设置当前拖拽索引
        this.draggingIndex = index;
        this.isTouchDragging = true;

        // 使用存储的固定宽高
        this.draggedItemRect = {
          width: this.fixedItemWidth,
          height: this.fixedItemHeight,
        };

        // 获取当前元素位置用于计算偏移 - 使用缓存的元素
        const gridItems = this.getCachedGridItems();
        const element = gridItems[index];
        if (element) {
          // 使用getBoundingClientRect获取视口中的位置
          const rect = element.getBoundingClientRect();
          
          // 计算触摸点相对于元素左上角的偏移
          this.touchOffsetX = this.touchStartX - rect.left;
          this.touchOffsetY = this.touchStartY - rect.top;

          // 创建拖拽克隆元素
          this.createDragClone(index);

          // 计算相对于outer-container的位置
          const containerRect = this.containerElement.getBoundingClientRect();
          this.dragCloneX = rect.left - containerRect.left;
          this.dragCloneY = rect.top - containerRect.top;
          this.isDragClone = true;

          // 立即更新位置
          this.updateDragClonePosition();

          requestAnimationFrame(() => {
            // 使用触摸点减去偏移来计算正确位置，相对于容器
            const targetX = this.touchStartX - this.touchOffsetX - containerRect.left;
            const targetY = this.touchStartY - this.touchOffsetY - containerRect.top;
            
            // 限制在容器范围内
            const maxX = containerRect.width - this.fixedItemWidth;
            const maxY = containerRect.height - this.fixedItemHeight;
            
            this.dragCloneX = Math.max(0, Math.min(targetX, maxX));
            this.dragCloneY = Math.max(0, Math.min(targetY, maxY));
            this.updateDragClonePosition();
          });

        }
      }
      if(!this.data.isEditing){
          setTimeout(()=>{
          this.selectIconClick(null, this.data.list[index], index)
        },100)
      }
      this.data.isEditing = true;
      this.$emit('onEditStateChanged', true);
      this.longPressTimer = null;
    },

    // 取消长按计时器
    cancelLongPress() {
      if (this.longPressTimer) {
        clearTimeout(this.longPressTimer);
        this.longPressTimer = null;
      }
    },

    // 触摸移动处理
    onTouchMove(e) {
      if (!this.isTouchDragging) return;

      // 确保在拖拽模式下阻止所有事件传播
      if (this.isTouchDragging && this.data.isEditing) {
        if (e.oriEvent) {
          e.oriEvent.preventDefault();
          e.oriEvent.stopPropagation();
          e.oriEvent.stopImmediatePropagation();
        }
      }

      const touch = e.changedTouches[0];

      // 更新目标位置而非直接设置
      this.targetTouchX = touch.pageX;
      this.targetTouchY = touch.pageY;

      // 启动平滑动画（如果尚未启动）
      if (!this.animationFrameId) {
        this.animationFrameId = requestAnimationFrame(this.optimizedUpdateDragPosition);
      }

      // 使用节流优化交换逻辑，增加节流时间减少频繁调用
      if (!this.updatePositionThrottled) {
        this.updatePositionThrottled = this.throttle(this.handleSwapLogic.bind(this), 500);
      }
      
      // 在动画过程中不执行交换逻辑
      if (!this.isAnimating) {
        this.updatePositionThrottled(touch.pageX, touch.pageY);
      }
    },

    // 简化的交换处理逻辑
    handleSwapLogic(touchX, touchY) {
      // 控制交换频率，避免过于频繁的交换
      const now = Date.now();
      if (now - this.lastSwapTime < 150) return; // 增加频率控制到150ms

      // 检查位置稳定性 - 如果触摸点基本没有移动，认为是稳定状态
      const moveDistance = Math.sqrt(
        Math.pow(touchX - this.lastTouchX, 2) + Math.pow(touchY - this.lastTouchY, 2)
      );
      
      if (moveDistance < 10) { // 移动距离小于10px认为是稳定的
        if (this.stablePositionTime === 0) {
          this.stablePositionTime = now;
        } else if (now - this.stablePositionTime > 300) {
          // 稳定超过300ms，跳过交换检测
          return;
        }
      } else {
        // 位置发生明显移动，重置稳定时间
        this.stablePositionTime = 0;
      }
      
      // 更新上次触摸位置
      this.lastTouchX = touchX;
      this.lastTouchY = touchY;

      // 获取容器边界
      const containerRect = this.containerElement.getBoundingClientRect();
      
      // 计算用于交换检测的有效触摸点
      // 如果触摸点在容器外，使用拖拽克隆元素的中心位置
      let effectiveTouchX = touchX;
      let effectiveTouchY = touchY;
      
      if (touchX < containerRect.left || touchX > containerRect.right || 
          touchY < containerRect.top || touchY > containerRect.bottom) {
        // 触摸点在容器外，使用拖拽克隆元素的中心位置
        const cloneCenterX = this.dragCloneX + this.fixedItemWidth / 2;
        const cloneCenterY = this.dragCloneY + this.fixedItemHeight / 2;
        effectiveTouchX = containerRect.left + cloneCenterX;
        effectiveTouchY = containerRect.top + cloneCenterY;
      }

      // 使用缓存的网格元素
      const gridItems = this.getCachedGridItems();
      let targetIndex = null;

      // 寻找有效触摸点所在的目标元素
      for (const item of gridItems) {
        const itemIndex = parseInt(item.getAttribute('data-index'), 10);
        if (itemIndex === this.draggingIndex) continue;

        const rect = item.getBoundingClientRect();

        // 有效触摸点是否在元素的中心区域内
        const centerX = (rect.left + rect.right) / 2;
        const centerY = (rect.top + rect.bottom) / 2;
        const halfWidth = rect.width * 0.3; // 缩小判断区域到30%，减少误触
        const halfHeight = rect.height * 0.3;

        // 检查有效触摸点是否在元素的中心区域内
        if (
          effectiveTouchX >= centerX - halfWidth &&
          effectiveTouchX <= centerX + halfWidth &&
          effectiveTouchY >= centerY - halfHeight &&
          effectiveTouchY <= centerY + halfHeight
        ) {
          targetIndex = itemIndex;
          break; // 找到第一个符合条件的就退出
        }
      }

      // 设置悬停高亮
      this.hoverIndex = targetIndex;

      // 执行交换
      if (targetIndex !== null && targetIndex !== this.draggingIndex) {
        // 防止在动画过程中频繁交换
        if (this.isAnimating) return;
        
        // 创建当前交换对的标识符
        const currentSwapPair = [this.draggingIndex, targetIndex].sort().join('-');
        
        // 如果这是同一对元素的重复交换，需要更严格的时间控制
        if (this.lastSwapPair === currentSwapPair) {
          if (now - this.lastSwapTime < 1000) return; // 同一对元素需要等待1秒
        }
        
        this.isAnimating = true;
        
        // 使用Vue的$set来避免触发不必要的重新渲染
        const temp = this.data.list[this.draggingIndex];
        this.$set(this.data.list, this.draggingIndex, this.data.list[targetIndex]);
        this.$set(this.data.list, targetIndex, temp);
        
        // 更新拖拽索引和交换记录
        this.draggingIndex = targetIndex;
        this.lastSwapTime = now;
        this.lastSwapPair = currentSwapPair;
        
        // 重置稳定位置时间，因为刚刚发生了交换
        this.stablePositionTime = 0;
        
        // 延迟清理缓存，等待DOM更新完成
        this.$nextTick(() => {
          setTimeout(() => {
            this.clearGridItemsCache();
            this.isAnimating = false;
          }, 100); // 增加延迟时间到100ms
        });
      }
    },



    // 元素本身的触摸结束
    endTouch(e) {
      this.$emit('onDragEventEnd', e);
      // 如果只是短按（还在计时），就取消长按
      this.cancelLongPress();
      // 如果正在拖拽中，确保清理状态
      if (this.isTouchDragging) {
        // 取消动画帧
        if (this.animationFrameId) {
          cancelAnimationFrame(this.animationFrameId);
          this.animationFrameId = null;
        }

        this.isTouchDragging = false;
        this.isDragClone = false;
        this.hoverIndex = null;
        this.isUpdatingPosition = false;
        
        // 重置交换状态
        this.lastSwapPair = null;
        this.stablePositionTime = 0;
        this.lastTouchX = 0;
        this.lastTouchY = 0;

        // 销毁拖拽克隆元素
        this.destroyDragClone();
        
        // 等待可能的交换动画完成后再清理
        setTimeout(() => {
          this.clearGridItemsCache();
          this.isAnimating = false; // 重置动画状态
        }, 100);

        // 使用延时来重置拖拽索引，避免与点击事件冲突
        setTimeout(() => {
          this.draggingIndex = null;
        }, 150);
      }
    },

    // 触摸结束处理 - 全局事件
    onTouchEnd(e) {
      // 取消动画帧
      if (this.animationFrameId) {
        cancelAnimationFrame(this.animationFrameId);
        this.animationFrameId = null;
      }

      // 重置拖拽状态
      this.isTouchDragging = false;
      this.isDragClone = false;
      this.hoverIndex = null;
      this.isUpdatingPosition = false;
      
      // 重置交换状态
      this.lastSwapPair = null;
      this.stablePositionTime = 0;
      this.lastTouchX = 0;
      this.lastTouchY = 0;

      // 销毁拖拽克隆元素
      this.destroyDragClone();
      
      // 延迟清理，确保所有动画和状态更新完成
      setTimeout(() => {
        this.clearGridItemsCache();
        this.isAnimating = false;
        this.draggingIndex = null;
      }, 100);
    },
    // 获取grid-box宽度的方法
    updateGridBoxWidth() {
      this.$nextTick(() => {
        const gridBoxes = document.querySelectorAll('.grid-item');
        if (gridBoxes && gridBoxes.length > 0) {
          const box = gridBoxes[0];
          this.gridBoxWidth = box.offsetWidth;

          // 更新text样式，确保不超出
          const textElements = document.querySelectorAll('.itemText');
          textElements.forEach((el) => {
            el.style.maxWidth = `${this.gridBoxWidth}px`;
          });
        }
      });
    },

    initLottieAnimations() {
      this.$nextTick(() => {
        // 清理之前的动画实例
        Object.keys(this.lottieAnimations).forEach((key) => {
          const anim = this.lottieAnimations[key];
          if (anim && typeof anim.destroy === 'function') {
            try {
              anim.removeEventListener('complete');
            } catch (e) {
              console.warn(`移除事件监听器失败: ${e.message}`);
            }
            anim.destroy();
          }
          delete this.lottieAnimations[key];
        });

        // 重置动画实例对象
        this.lottieAnimations = {};

        // 延迟一点时间确保DOM完全更新并且之前的动画已被销毁
        setTimeout(() => {
          // 为每个列表项初始化动画
          this.data.list.forEach((item) => {
            this.initItemAnimations(item);
          });
        }, 50); // 小延迟确保DOM已更新和旧动画已销毁
      });
    },

    // 添加新方法用于获取和存储固定宽高
    updateFixedItemSize() {
      this.$nextTick(() => {
        const gridItem = document.querySelector('.grid-item');
        if (gridItem) {
          const rect = gridItem.getBoundingClientRect();
          this.fixedItemWidth = rect.width;
          this.fixedItemHeight = rect.height;
        }
      });
    },

    // 暂未使用，但保留用于将来扩展
    leftTopIconClick(e) {
      e.preventDefault();
      e.stopPropagation();
      // 这里可以添加将来的处理逻辑
      return false;
    },
  },
  watch: {
    // 监听列表数据变化，自动更新缓存
    'data.list': {
      handler(newList, oldList) {
        // 跳过拖拽期间的更新，提高性能
        if (this.isTouchDragging) {
          return;
        }
        // 更精确的变化检测
        const hasLengthChange = newList.length !== oldList.length;
        if (hasLengthChange) {
          
          // 清除DOM缓存
          this.clearGridItemsCache();
          
          // 使用防抖处理列表变化
          if (!this.listChangeDebounced) {
            this.listChangeDebounced = this.debounce(() => {
              this.$nextTick(() => {
                // 优化内存使用
                // 确保每个项目都有完整的数据结构
                if (newList && Array.isArray(newList)) {
                  newList.forEach((item, index) => {
                    this.ensureItemStructure(item);
                  });
                }
                
                this.optimizeMemoryUsage();
              });
            }, 100);
          }
          this.listChangeDebounced();
        }
      },
      deep: true,
    },
  },
  updated(){
    if(this.isTouchDragging){return}
  },
  mounted() {
    
    // 确保初始数据结构完整性
    if (this.data && this.data.list && Array.isArray(this.data.list)) {
      this.data.list.forEach((item, index) => {
        this.ensureItemStructure(item);
      });
    }
    
    // 缓存容器元素
    this.containerElement = this.$el;
    
    // 初始获取grid-box宽度
    this.updateGridBoxWidth();
    // 获取并存储固定宽高
    this.updateFixedItemSize();
    // 初始化Lottie动画
    this.initLottieAnimations();
    
    // 初始化节流函数
    this.updatePositionThrottled = this.throttle(this.handleSwapLogic.bind(this), 100);
  },
  beforeDestroy() {
    // 确保清理所有事件监听器
    this.cancelLongPress();
    // 清理动画帧
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
      this.animationFrameId = null;
    }
    // 清理拖拽克隆元素
    this.destroyDragClone();
    
    // 清理缓存
    this.clearGridItemsCache();
    
    // 清理节流和防抖函数
    this.updatePositionThrottled = null;
    this.listChangeDebounced = null;
    
    // 清理容器引用
    this.containerElement = null;
  },
  created() {
    // 组件创建时无需预处理数据，使用时按需获取全局数据
  },
};
</script>

<style scoped>
button {
  border: none;
}

.disabled-item {
  opacity: 0.6;
  pointer-events: none;
}

.outer-container {
  width: 100%;
  position: relative;
  z-index: 1;
  /* 确保容器可以作为拖拽克隆元素的定位父元素 */
  overflow: visible;
}

.items-container {
  width: 100%;
}

.grid-items-wrapper {
  width: 100%;
  position: relative;
}

.grid-inner-wrapper {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), 1fr);
  grid-gap: var(--grid-gap);
  width: calc(100% - var(--grid-margin));
  /* 性能优化 */
  contain: layout style paint;
  transform: translateZ(0);
}

/* 优化排序过渡效果 */
.grid-fade-move {
  transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  will-change: transform;
}

.grid-item {
  position: relative;
  box-sizing: border-box;
  transition: all 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  will-change: transform, opacity, box-shadow;
  overflow: hidden;
  z-index: 1;
  /* 性能优化 */
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
}

.grid-box {
  position: relative;
  display: flex;
  justify-content: space-between;
  flex-direction: column;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  height: auto;
}

.leftTopIcon {
  position: fixed;
  left: 0;
  top: 0;
}

.actionButton {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Lottie容器样式 */
.lottie-container {
  position: absolute;
  overflow: hidden;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  pointer-events: none;
}

.bg-anim,
.front-anim {
  z-index: 1;
  width: 100%;
  height: 100%;
}

.bg-anim,
.front-anim {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

/* 当进入编辑模式时给所有元素添加淡淡的阴影 */
/* .editMode .grid-item:not(.being-dragged):not(.hidden) {
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
} */

/* 悬停目标的样式 */
.hover-target {
  z-index: 50;
  transform: scale(1.05);
  transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  position: relative;
}

/* 正在拖拽的元素样式 */
.being-dragged {
  z-index: 100;
  opacity: 0.3;
  position: relative;
}

/* 被拖拽时原位置隐藏 */
.grid-item.hidden {
  opacity: 0 !important;
  visibility: hidden;
}

/* 拖拽克隆元素样式（现在通过JavaScript动态应用） */
.drag-clone-dynamic {
  position: absolute;
  z-index: 9999;
  pointer-events: none;
  user-select: none;
  box-sizing: border-box;
  transform-origin: center center;
  /* 确保拖拽克隆元素不会超出容器边界 */
  max-width: 100%;
  max-height: 100%;
  overflow: hidden;
}

.flexBox {
  display: flex;
  justify-content: space-between;
  width: 100%;
  position: relative;
  flex-direction: row;
}

.itemText {
  display: block;
  width: 80%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.shaking {
  animation: shake 0.6s infinite;
  transform-origin: center center;
}

/* 抖动关键帧 */
@keyframes shake {
  0% {
    transform: rotateZ(2deg);
  }

  25% {
    transform: rotateZ(-2deg);
  }

  50% {
    transform: rotateZ(2deg);
  }

  75% {
    transform: rotateZ(-2deg);
  }

  100% {
    transform: rotateZ(2deg);
  }
}


</style>
