<template>
  <div class="app-container ems-overview">
    <div class="toolbar">
      <div class="toolbar-left">
        <el-button-group>
          <el-button size="mini" :type="viewLevel===1?'primary':'default'" @click="setView(1)">1</el-button>
          <el-button size="mini" :type="viewLevel===2?'primary':'default'" @click="setView(2)">2</el-button>
          <el-button size="mini" :type="viewLevel===3?'primary':'default'" @click="setView(3)">3</el-button>
        </el-button-group>
        <el-input
          size="mini"
          v-model="query.keyword"
          placeholder="据位/设备关键词"
          clearable
          class="q-input"
          @keyup.enter.native="handleQuery"
        />
        <el-button size="mini" type="primary" @click="handleQuery">查询</el-button>
        <el-button size="mini" @click="resetQuery">重置查询</el-button>
      </div>
      <div class="toolbar-right">
        <el-button size="mini" icon="el-icon-zoom-in" @click="zoom(1.1)"/>
        <el-button size="mini" icon="el-icon-zoom-out" @click="zoom(0.9)"/>
        <el-button size="mini" icon="el-icon-refresh" @click="resetView">重置视图</el-button>
      </div>
    </div>

    <div class="canvas-wrapper" ref="wrapper">
      <svg :viewBox="viewBox" class="overview-svg">
        <!-- 区域：由矩形拼接组成 -->
        <g
          v-for="area in areas"
          :key="area.id"
          style="cursor:pointer;"
          @click="selectArea(area, $event)"
        >
          <!-- 拼接矩形 -->
          <g v-for="(shape, idx) in area.shapes" :key="area.id + '_s_' + idx">
            <rect
              :x="shape.x"
              :y="shape.y"
              :width="shape.w"
              :height="shape.h"
              :fill="area.id===selectedAreaId ? area.fillActive : area.fill"
              :stroke="area.stroke"
              :stroke-width="2"
              :opacity="viewLevel===3 ? 0.8 : 1"
              rx="4"
              ry="4"
            />
          </g>

          <!-- 区域标题 -->
          <text :x="area.labelPos.x" :y="area.labelPos.y" class="area-label">
            {{ area.name }}
          </text>

          <!-- 点位格子（方/长方形） -->
          <g v-if="viewLevel!==1 || area.id===selectedAreaId">
            <g
              v-for="pt in area.pointsInfo"
              :key="pt.id"
              @click.stop="openPoint(pt, area, $event)"
              style="cursor:pointer;"
            >
              <rect
                :x="pt.x-pt.w/2"
                :y="pt.y-pt.h/2"
                :width="pt.w"
                :height="pt.h"
                rx="4"
                ry="4"
                :fill="ptFill(pt)"
                stroke="#444"
                :stroke-width="selectedPoint && selectedPoint.id===pt.id ? 2 : 1"
                :opacity="viewLevel===2 ? 0.9 : 0.8"
                :class="{'pt-highlight': highlightedIds.has(pt.id)}"
              />
              <text :x="pt.x" :y="pt.y-6" class="pt-title">{{ pt.name }}</text>
              <text :x="pt.x" :y="pt.y+10" class="pt-sub">
                {{ safeMetric(pt, 'metric1', 'label', '指标1') + '：' + safeMetric(pt, 'metric1', 'value', '--') }}
              </text>
              <text :x="pt.x" :y="pt.y+24" class="pt-sub">
                {{ safeMetric(pt, 'metric2', 'label', '指标2') + '：' + safeMetric(pt, 'metric2', 'value', '--') }}
              </text>
            </g>
          </g>
        </g>
      </svg>

      <!-- 悬浮信息卡（点击块/点位时显示） -->
      <div
        v-if="infoBox.show"
        class="info-box"
        :style="{ left: infoBox.x + 'px', top: infoBox.y + 'px' }"
      >
        <div class="info-title">{{ infoBox.title }}</div>
        <div class="info-line" v-for="(line, i) in infoBox.lines" :key="i">{{ line }}</div>
      </div>
    </div>

    <!-- 点位详情 -->
    <el-dialog
      title="点位详情"
      :visible.sync="pointDialogOpen"
      width="420px"
      append-to-body
    >
      <div v-if="selectedPoint">
        <p>点位名称：{{ selectedPoint.name }}</p>
        <p>所属区域：{{ selectedArea ? selectedArea.name : '-' }}</p>
        <p>坐标：({{ selectedPoint.x }}, {{ selectedPoint.y }})</p>
        <el-divider></el-divider>
        <p>设备数据：</p>
        <ul class="point-ul">
          <li>
            {{ safeMetric(selectedPoint, 'metric1', 'label', '指标1') }}：
            {{ safeMetric(selectedPoint, 'metric1', 'value', '--') }}
          </li>
          <li>
            {{ safeMetric(selectedPoint, 'metric2', 'label', '指标2') }}：
            {{ safeMetric(selectedPoint, 'metric2', 'value', '--') }}
          </li>
        </ul>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button size="mini" type="primary" @click="pointDialogOpen=false">关 闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
// @ts-nocheck
export default {
  name: 'EmsOverview',
  data() {
    return {
      viewLevel: 1, // 1/2/3 切换视图
      scale: 1,
      viewBox: '0 0 1200 700',
      selectedAreaId: null,
      selectedPoint: null,
      selectedArea: null,
      pointDialogOpen: false,

      // 查询
      query: {
        keyword: ''
      },
      highlightedIds: new Set(),

      infoBox: {
        show: false,
        x: 0,
        y: 0,
        title: '',
        lines: []
      },

      // 示例数据：使用由正方形/长方形拼接的区域形状
      areas: [
        {
          id: 'A',
          name: '冷藏区',
          // 用多个长方形拼接
          shapes: [
            { x: 40, y: 60, w: 560, h: 560 }, // 大矩形
            { x: 40, y: 620, w: 560, h: 10 }  // 底部细条，强调边界（可选）
          ],
          labelPos: { x: 60, y: 110 },
          fill: '#4c6ef5',
          fillActive: '#3b5bdb',
          stroke: '#2b2d42',
          // 点位
          pointsInfo: [
            {
              id: 'A1', name: '点位-01', x: 250, y: 220, w: 110, h: 70,
              deviceData: { metric1: { label: '温度', value: '4.2℃' }, metric2: { label: '状态', value: '正常' } }
            },
            {
              id: 'A2', name: '点位-02', x: 520, y: 260, w: 110, h: 70,
              deviceData: { metric1: { label: '温度', value: '5.1℃' }, metric2: { label: '状态', value: '正常' } }
            },
            {
              id: 'A3', name: '点位-03', x: 420, y: 420, w: 110, h: 70,
              deviceData: { metric1: { label: '温度', value: '7.8℃' }, metric2: { label: '状态', value: '告警' } }
            }
          ],
          // 库存示例（点击区域显示）
          inventory: { title: '库存', count: 31890 }
        },
        {
          id: 'B',
          name: '冷冻区',
          shapes: [
            { x: 620, y: 60, w: 520, h: 280 }, // 上部
            { x: 620, y: 350, w: 520, h: 270 } // 下部
          ],
          labelPos: { x: 640, y: 110 },
          fill: '#4ea8de',
          fillActive: '#3a86ff',
          stroke: '#1b263b',
          pointsInfo: [
            {
              id: 'B1', name: '点位-11', x: 780, y: 220, w: 110, h: 70,
              deviceData: { metric1: { label: '温度', value: '-12.3℃' }, metric2: { label: '状态', value: '正常' } }
            },
            {
              id: 'B2', name: '点位-12', x: 980, y: 460, w: 110, h: 70,
              deviceData: { metric1: { label: '温度', value: '-10.0℃' }, metric2: { label: '状态', value: '维护' } }
            }
          ],
          inventory: { title: '库存', count: 21890 }
        },
        // 分拣区：原来是不规则多边形，现改为由多个矩形拼接成“侧边栏”效果
        {
          id: 'C',
          name: '分拣区',
          shapes: [
            { x: 1160, y: 60,  w: 20,  h: 560 }, // 竖条边框
            { x: 1080, y: 60,  w: 70,  h: 130 },
            { x: 1080, y: 200, w: 70,  h: 130 },
            { x: 1080, y: 340, w: 70,  h: 130 },
            { x: 1080, y: 480, w: 70,  h: 140 }
          ],
          labelPos: { x: 1090, y: 90 },
          fill: '#95d5b2',
          fillActive: '#74c69d',
          stroke: '#2d6a4f',
          pointsInfo: [
            {
              id: 'C1', name: '能量棒', x: 1115, y: 130, w: 60, h: 60,
              deviceData: { metric1: { label: '重量', value: '1000g' }, metric2: { label: '状态', value: '良好' } }
            },
            {
              id: 'C2', name: '显卡', x: 1115, y: 270, w: 60, h: 60,
              deviceData: { metric1: { label: '型号', value: '4001' }, metric2: { label: '状态', value: '正常' } }
            },
            {
              id: 'C3', name: '特种钢', x: 1115, y: 410, w: 60, h: 60,
              deviceData: { metric1: { label: '数量', value: '999个' }, metric2: { label: '状态', value: '正常' } }
            },
            {
              id: 'C4', name: '能量棒', x: 1115, y: 560, w: 60, h: 60,
              deviceData: { metric1: { label: '重量', value: '500g' }, metric2: { label: '状态', value: '正常' } }
            }
          ],
          inventory: { title: '库存', count: 4080 }
        }
      ]
    };
  },
  methods: {
    setView(n) {
      this.viewLevel = n;
    },
    zoom(factor) {
      this.scale = Math.max(0.5, Math.min(2.5, this.scale * factor));
      const base = { w: 1200, h: 700 };
      const w = base.w / this.scale;
      const h = base.h / this.scale;
      this.viewBox = `0 0 ${w} ${h}`;
    },
    resetView() {
      this.scale = 1;
      this.viewBox = '0 0 1200 700';
      this.selectedAreaId = null;
      this.selectedPoint = null;
      this.selectedArea = null;
      this.hideInfo();
      this.highlightedIds = new Set();
    },

    // 安全读取设备指标
    safeMetric(obj, mKey, fKey, defVal) {
      if (!obj || !obj.deviceData) return defVal;
      const m = obj.deviceData[mKey];
      return m && m[fKey] != null ? m[fKey] : defVal;
    },

    // 点位填充色
    ptFill(pt) {
      const val = (this.safeMetric(pt, 'metric2', 'value', '') || '').toString();
      if (val.includes('告警') || val.includes('异常')) return '#ff6b6b';
      if (val.includes('维护')) return '#ffd166';
      return '#8ecae6';
    },

    // 区域选择 + 信息卡显示（库存）
    selectArea(area, evt) {
      this.selectedAreaId = area.id;
      this.selectedArea = area;
      this.showInfo(evt, area.name, [
        area.inventory?.title || '库存',
        `库存数量：${this.formatNumber(area.inventory?.count ?? 0)}`
      ]);
    },

    // 打开点位（弹框 + 信息卡）
    openPoint(pt, area, evt) {
      this.selectedPoint = pt;
      this.selectedArea = area;
      this.pointDialogOpen = true;

      const l1 = `${this.safeMetric(pt, 'metric1', 'label', '指标1')}：${this.safeMetric(pt, 'metric1', 'value', '--')}`;
      const l2 = `${this.safeMetric(pt, 'metric2', 'label', '指标2')}：${this.safeMetric(pt, 'metric2', 'value', '--')}`;
      this.showInfo(evt, pt.name, [l1, l2]);
    },

    // 悬浮信息卡
    showInfo(evt, title, lines) {
      const wrap = this.$refs.wrapper;
      if (!wrap) return;
      const rect = wrap.getBoundingClientRect();
      const x = evt.clientX - rect.left + 12;
      const y = evt.clientY - rect.top + 12;
      this.infoBox = { show: true, x, y, title, lines };
    },
    hideInfo() {
      this.infoBox.show = false;
    },

    // 查询（据位查询）：优先走接口，失败回退本地过滤
    async handleQuery() {
      const kw = (this.query.keyword || '').trim();
      this.highlightedIds = new Set();
      if (!kw) {
        this.hideInfo();
        return;
      }
      let usedApi = false;
      try {
        // 存在封装的 API 则调用
        if (this.$api && this.$api.ems && this.$api.ems.queryPoints) {
          await this.queryPoints({ keyword: kw });
          usedApi = true;
        }
      } catch (e) {
        // 忽略接口错误，回退本地
        usedApi = false;
      }

      // 高亮与信息卡（对当前 this.areas 数据集进行）
      let firstHit = null;
      this.areas.forEach(area => {
        (area.pointsInfo || []).forEach(pt => {
          const text = [
            pt.name,
            this.safeMetric(pt, 'metric1', 'label', ''),
            this.safeMetric(pt, 'metric1', 'value', ''),
            this.safeMetric(pt, 'metric2', 'label', ''),
            this.safeMetric(pt, 'metric2', 'value', '')
          ].join(' ');
          if (text.includes(kw)) {
            this.highlightedIds.add(pt.id);
            if (!firstHit) firstHit = { pt, area };
          }
        });
      });

      if (firstHit) {
        this.selectedAreaId = firstHit.area.id;
        this.selectedArea = firstHit.area;
        this.selectedPoint = firstHit.pt;
        const wrap = this.$refs.wrapper;
        if (wrap) {
          const rect = wrap.getBoundingClientRect();
          const x = (firstHit.pt.x / (1200 / rect.width)) + 12;
          const y = (firstHit.pt.y / (700 / rect.height)) + 12;
          this.infoBox = {
            show: true,
            x: Math.min(rect.width - 220, Math.max(8, x)),
            y: Math.min(rect.height - 140, Math.max(8, y)),
            title: firstHit.pt.name,
            lines: [
              `${this.safeMetric(firstHit.pt, 'metric1', 'label', '指标1')}：${this.safeMetric(firstHit.pt, 'metric1', 'value', '--')}`,
              `${this.safeMetric(firstHit.pt, 'metric2', 'label', '指标2')}：${this.safeMetric(firstHit.pt, 'metric2', 'value', '--')}`
            ]
          };
        }
      } else {
        this.$message.info(usedApi ? '接口无匹配结果' : '未查询到匹配点位/设备数据');
        this.hideInfo();
      }
    },
    resetQuery() {
      this.query.keyword = '';
      this.highlightedIds = new Set();
      this.hideInfo();
    },

    // 对接接口：据位查询或区域点位拉取
    queryPoints(params) {
      if (!(this.$api && this.$api.ems && this.$api.ems.queryPoints)) {
        return Promise.resolve();
      }
      return this.$api.ems.queryPoints(params).then(res => {
        const data = (res && (res.data ?? res)) || {};
        // 结构 A：包含 areas
        if (Array.isArray(data.areas)) {
          // 将后端 areas 适配为前端结构，缺省字段从现有同 id 区域继承
          const existMap = new Map(this.areas.map(a => [a.id, a]));
          this.areas = data.areas.map(a => {
            const old = existMap.get(a.id) || {};
            return {
              id: a.id,
              name: a.name ?? old.name ?? '',
              shapes: Array.isArray(a.shapes) ? a.shapes : (old.shapes || []),
              labelPos: a.labelPos ?? old.labelPos ?? { x: 60, y: 110 },
              fill: old.fill || '#4c6ef5',
              fillActive: old.fillActive || '#3b5bdb',
              stroke: old.stroke || '#2b2d42',
              inventory: a.inventory ?? old.inventory ?? null,
              pointsInfo: Array.isArray(a.points)
                ? a.points.map(p => ({
                    id: p.id, name: p.name,
                    x: p.x, y: p.y, w: p.w, h: p.h,
                    deviceData: p.deviceData || {}
                  }))
                : (old.pointsInfo || [])
            };
          });
          return;
        }
        // 结构 B：仅返回 points（需含 areaId）
        if (Array.isArray(data.points)) {
          const byArea = {};
          data.points.forEach(p => {
            const aid = p.areaId;
            if (!aid) return;
            (byArea[aid] = byArea[aid] || []).push({
              id: p.id, name: p.name,
              x: p.x, y: p.y, w: p.w, h: p.h,
              deviceData: p.deviceData || {}
            });
          });
          this.areas = this.areas.map(a => ({
            ...a,
            pointsInfo: byArea[a.id] ? byArea[a.id] : (a.pointsInfo || [])
          }));
          // 可选：data.areasInfo 覆盖库存
          if (Array.isArray(data.areasInfo)) {
            const infoMap = new Map(data.areasInfo.map(i => [i.id || i.areaId, i]));
            this.areas = this.areas.map(a => ({
              ...a,
              inventory: infoMap.get(a.id)?.inventory ?? a.inventory
            }));
          }
          return;
        }
        // 未识别结构，保持不变
      }).catch(err => {
        this.$message.error('查询接口失败');
        // 继续走本地回退
      });
    },

    formatNumber(n) {
      const str = (n ?? 0).toString();
      return str.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    }
  }
};
</script>

<style scoped>
.ems-overview {
  display: flex;
  flex-direction: column;
  width: 100%;
}
.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.toolbar-left {
  display: flex;
  align-items: center;
  gap: 8px;
}
.q-input {
  width: 220px;
}
.toolbar-right {
  display: flex;
  gap: 6px;
  align-items: center;
}

.canvas-wrapper {
  border: 1px solid #e5e7eb;
  border-radius: 6px;
  background: #f8fafc;
  height: 720px;
  position: relative;
  overflow: hidden;
}
.overview-svg {
  width: 100%;
  height: 100%;
}
.area-label {
  fill: #ffffff;
  font-size: 16px;
  font-weight: 700;
  text-shadow: 0 1px 1px rgba(0,0,0,0.2);
}
.pt-title, .pt-sub {
  fill: #ffffff;
  font-size: 12px;
  text-anchor: middle;
  user-select: none;
  pointer-events: none;
}
.pt-highlight {
  stroke: #ffb703 !important;
  stroke-width: 3 !important;
}

.info-box {
  position: absolute;
  min-width: 180px;
  max-width: 240px;
  background: #fff;
  color: #111827;
  box-shadow: 0 6px 20px rgba(0,0,0,0.18);
  border-radius: 8px;
  padding: 10px 12px;
  z-index: 10;
  pointer-events: none;
}
.info-title {
  font-weight: 600;
  margin-bottom: 6px;
}
.info-line {
  font-size: 12px;
  line-height: 18px;
}

.point-ul {
  margin: 0;
  padding-left: 16px;
}
</style>