<template>
  <div class="app-container flow-page">
    <div class="flow-tabs">
      <span
        v-for="tab in tabs"
        :key="tab.key"
        class="flow-tab-item"
        :class="{ active: activeTab === tab.key }"
        @click="switchTab(tab.key)"
      >
        <i :class="tab.icon"></i>
        {{ tab.label }}
      </span>
    </div>

    <div class="flow-toolbar">
      <el-dropdown trigger="click" @command="handleDownload">
        <el-button size="small" type="primary" plain>
          <i class="el-icon-download"></i> 下载流程图
          <i class="el-icon-arrow-down el-icon--right"></i>
        </el-button>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item command="svg">下载 SVG</el-dropdown-item>
          <el-dropdown-item command="png">下载 PNG</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
    </div>

    <div v-loading="loading" class="flow-content">
      <div ref="diagram" class="flow-diagram" v-html="currentSvg" @click="onNodeClick"></div>
    </div>
  </div>
</template>

<script>
import { renderMermaidSVG, THEMES } from 'beautiful-mermaid'

const theme = {
  ...THEMES['zinc-light'],
  padding: 24,
  nodeSpacing: 28,
  layerSpacing: 44,
  font: 'Inter, "Microsoft YaHei", sans-serif',
}

const diagrams = {
  afterSales: `
graph TD
  A["<b>创建售后单</b><br/>填写基本信息<br/>选择需售后处理的钢卷"]:::step
  A --> B["<b>多部门并行处理</b>"]:::fork
  B --> C["<b>生产部</b><br/>出具处理意见"]:::dept1
  B --> D["<b>质量部</b><br/>出具处理意见"]:::dept2
  B --> E["<b>销售部</b><br/>出具处理意见"]:::dept3
  C --> F{"三个部门<br/>全部提交?"}:::decision
  D --> F
  E --> F
  F -->|已全部提交| G["<b>售后负责人</b><br/>汇总各部门意见<br/>形成最终处理方案<br/>指定执行部门"]:::approve
  G --> H["<b>部门执行</b><br/>执行处理方案"]:::execute
  H --> I["<b>返回执行结果</b><br/>提交执行报告"]:::result
  I --> J(["<b>售后单封存</b><br/>流程结束"]):::end

  classDef step fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
  classDef fork fill:#f0f5ff,stroke:#409eff,color:#303133,stroke-width:2px
  classDef dept1 fill:#e6fffa,stroke:#00b4a0,color:#303133,stroke-width:2px
  classDef dept2 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
  classDef dept3 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
  classDef decision fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
  classDef approve fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
  classDef execute fill:#fffbe6,stroke:#fadb14,color:#303133,stroke-width:2px
  classDef result fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
  classDef end fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
  linkStyle default stroke:#bfbfbf,stroke-width:2px
`,

  steelFullChain: `
graph TD
  A["<b>销售部创建合同</b><br/>录入产品所需内容<br/>规格/数量/技术标准"]:::s1

  A --> B["<b>原料卷到货</b>"]:::s2
  B --> C["<b>入库验收</b>"]:::s2
  C --> D["<b>登记原料库存</b>"]:::s2

  D --> E["<b>成品钢卷加工</b>"]:::s3

  E --> F["加工前质检"]:::s3qc
  E --> G["加工中质检"]:::s3qc
  E --> H["加工完工质检"]:::s3qc

  F --> I["<b>登记质量缺陷</b><br/>各工序均可录入"]:::s3
  G --> I
  H --> I

  I --> J["<b>质量等级判定</b><br/>依据质检标准"]:::s3
  J --> K["<b>单卷档案</b><br/>缺陷记录与等级<br/>全程绑定留存"]:::s3

  K --> L["<b>编排发货计划</b><br/>基于合同信息"]:::s4
  L --> M["<b>生成发货单</b>"]:::s4
  M --> N{"<b>发货质量校验</b><br/>缺陷/等级检查"}:::dec
  N -->|达标| O["<b>出库发货</b>"]:::s4
  N -->|不达标| P["<b>禁止出库</b>"]:::s5

  K --> Q["<b>钢卷库存管理</b>"]:::s4
  Q --> R["<b>逻辑库</b><br/>按功能/用途分类"]:::s4
  Q --> S["<b>物理库</b><br/>实际存放场地"]:::s4
  R --> T["<b>跨库/跨区调拨</b>"]:::s4
  S --> T
  T --> U["<b>实时更新库存数据</b>"]:::s4

  E --> V{"<b>生产过程<br/>数据异常检测</b>"}:::dec
  V -->|异常| W["<b>自动触发告警</b><br/>推送异常信息至<br/>业务人员核查处置"]:::s5

  K --> X["<b>生产数据报表统计</b><br/>原料/加工/质检<br/>库存/发货全周期汇总"]:::s4

  classDef s1 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
  classDef s2 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
  classDef s3 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
  classDef s3qc fill:#fffbe6,stroke:#fadb14,color:#303133,stroke-width:2px
  classDef s4 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef s5 fill:#fff1f0,stroke:#f5222d,color:#303133,stroke-width:2px
  classDef dec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
  linkStyle default stroke:#bfbfbf,stroke-width:2px
`,

  inventoryCheck: `
graph TD
  A["<b>创建盘库计划</b><br/>填写基本信息"]:::c1

  A --> B["<b>创建计划明细</b><br/>可创建多个明细"]:::c2

  B --> C["<b>选择库区</b><br/>逻辑库 / 实际库<br/>至少选一个"]:::c3
  C --> D["<b>生成系统库存快照</b>"]:::c4
  D --> E["<b>上传实盘库存Excel</b>"]:::c5
  E --> F["<b>执行对比</b><br/>快照 vs 实盘<br/>自动计算差异"]:::c6

  F --> G["<b>查看差异明细</b><br/>保存差异并填写处理方式"]:::c7
  G --> H["<b>提交送审</b>"]:::c8

  H --> I{"审批"}:::dec
  I -->|不通过| J["<b>退回修改</b>"]:::c7
  J --> G
  I -->|通过| K["<b>开始处理差异</b><br/>逐项执行处理方式"]:::c9

  K --> L{"所有差异<br/>处理完成?"}:::dec
  L -->|否| K
  L -->|是| M(["<b>完结流程</b><br/>盘库结束"]):::cend

  classDef c1 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
  classDef c2 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
  classDef c3 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
  classDef c4 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef c5 fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
  classDef c6 fill:#fffbe6,stroke:#fadb14,color:#606266,stroke-width:2px
  classDef c7 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef c8 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
  classDef c9 fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
  classDef dec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
  classDef cend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
  linkStyle default stroke:#bfbfbf,stroke-width:2px
`,

  productionSchedule: `
graph TD
  A["<b>创建需求单</b><br/>填写基本信息"]:::p1

  A --> B["<b>选择合同</b><br/>可选一个或多个合同"]:::p2
  B --> C["<b>自动获取需求明细</b><br/>从所选合同提取"]:::p3
  C --> D["<b>调整需求明细</b><br/>可编辑/修改/补充"]:::p4

  D --> E["<b>提交审批</b>"]:::p5
  E --> F{"审批"}:::dec
  F -->|不通过| G["<b>退回修改</b>"]:::p4
  G --> D
  F -->|通过| H["<b>转化为排产单</b>"]:::p6

  H --> I["<b>排产单</b><br/>可再次编辑"]:::p7
  I --> J["<b>再次提交审批</b>"]:::p5
  J --> K{"审批"}:::dec
  K -->|不通过| L["<b>退回修改</b>"]:::p7
  L --> I
  K -->|通过| M["<b>提交给车间</b>"]:::p8

  M --> N["<b>车间绑定钢卷</b><br/>每个排产计划<br/>绑定一个或多个钢卷"]:::p9
  N --> O["<b>执行生产</b>"]:::p10
  O --> P(["<b>排产完结</b>"]):::pend

  classDef p1 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
  classDef p2 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
  classDef p3 fill:#fff7e6,stroke:#fa8c16,color:#303133,stroke-width:2px
  classDef p4 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef p5 fill:#e6f7ff,stroke:#1890ff,color:#303133,stroke-width:2px
  classDef p6 fill:#fffbe6,stroke:#fadb14,color:#606266,stroke-width:2px
  classDef p7 fill:#fff0f6,stroke:#eb2f96,color:#303133,stroke-width:2px
  classDef p8 fill:#f6ffed,stroke:#52c41a,color:#303133,stroke-width:2px
  classDef p9 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef p10 fill:#fffbe6,stroke:#fadb14,color:#303133,stroke-width:2px
  classDef dec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
  classDef pend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
  linkStyle default stroke:#bfbfbf,stroke-width:2px
`,

  equipmentRepair: `
graph TD
  A["<b>创建维修计划</b>"]:::e1
  A1["点选异常巡检记录<br/>绑定记录与异常设备"]:::e1sub
  A --> A1

  A1 --> B["<b>提交审批</b>"]:::e2
  B --> C{"审批"}:::edec
  C -->|不通过| D["<b>退回修改</b>"]:::e1
  D --> A1
  C -->|通过| E["<b>逐设备维修记录</b><br/>逐一执行设备维修<br/>记录维修过程与结果"]:::e3

  E --> F{"全部设备<br/>维修完成?"}:::edec
  F -->|否| E
  F -->|是| G(["<b>流程结束</b>"]):::eend

  classDef e1 fill:#e6fffa,stroke:#13c2c2,color:#303133,stroke-width:2px
  classDef e1sub fill:#e6fffa,stroke:#13c2c2,color:#606266,stroke-width:1px,stroke-dasharray:3 3
  classDef e2 fill:#409eff,stroke:#337ecc,color:#fff,stroke-width:2px
  classDef e3 fill:#f0f5ff,stroke:#597ef7,color:#303133,stroke-width:2px
  classDef edec fill:#f9f0ff,stroke:#722ed1,color:#303133,stroke-width:2px
  classDef eend fill:#dcf7e8,stroke:#52c41a,color:#303133,stroke-width:2px,rx:10,ry:10
  linkStyle default stroke:#bfbfbf,stroke-width:2px
`,
}

export default {
  name: 'FlowChart',
  data() {
    return {
      loading: false,
      activeTab: 'steelFullChain',
      tabs: [
        { key: 'steelFullChain', label: '生产全链路流程', icon: 'el-icon-s-operation' },
        { key: 'afterSales', label: '售后处理流程', icon: 'el-icon-s-claim' },
        { key: 'inventoryCheck', label: '盘库流程', icon: 'el-icon-s-check' },
        { key: 'productionSchedule', label: '排产流程', icon: 'el-icon-s-order' },
        { key: 'equipmentRepair', label: '设备维修流程', icon: 'el-icon-s-tools' },
      ],
      svgCache: {},
      selectedNode: null,
      downloadLoading: false,
    }
  },
  watch: {
    currentSvg() {
      this.$nextTick(() => {
        this.bindNodeEvents()
      })
    },
  },
  computed: {
    currentSvg() {
      const code = diagrams[this.activeTab]
      if (!code) return ''
      if (!this.svgCache[this.activeTab]) {
        try {
          this.svgCache[this.activeTab] = renderMermaidSVG(code, theme)
        } catch (e) {
          console.error('Mermaid render error:', e)
          return '<p style="color:#f5222d;text-align:center;">流程图渲染失败: ' + e.message + '</p>'
        }
      }
      return this.svgCache[this.activeTab]
    },
  },
  methods: {
    handleDownload(format) {
      if (format === 'svg') {
        this.downloadSvg()
      } else if (format === 'png') {
        this.downloadPng()
      }
    },
    downloadSvg() {
      const svgEl = this.$refs.diagram?.querySelector('svg')
      if (!svgEl) {
        this.$message.warning('流程图尚未渲染完成')
        return
      }
      const clone = svgEl.cloneNode(true)
      const serializer = new XMLSerializer()
      const source = serializer.serializeToString(clone)
      const blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' })
      this.triggerDownload(URL.createObjectURL(blob), `${this.activeTab}.svg`)
      this.$message.success('SVG 已下载')
    },
    downloadPng() {
      const svgEl = this.$refs.diagram?.querySelector('svg')
      if (!svgEl) {
        this.$message.warning('流程图尚未渲染完成')
        return
      }
      this.downloadLoading = true

      const clone = svgEl.cloneNode(true)
      const serializer = new XMLSerializer()
      let source = serializer.serializeToString(clone)
      source = source.replace(/<\/?foreignObject[^>]*>/gi, '').replace(/<\/?style[^>]*>/gi, '')

      const svgBlob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' })
      const url = URL.createObjectURL(svgBlob)

      const img = new Image()
      img.onload = () => {
        const canvas = document.createElement('canvas')
        const rect = svgEl.getBoundingClientRect()
        const scale = 2
        canvas.width = rect.width * scale
        canvas.height = rect.height * scale
        const ctx = canvas.getContext('2d')
        ctx.scale(scale, scale)
        ctx.drawImage(img, 0, 0, rect.width, rect.height)
        URL.revokeObjectURL(url)
        canvas.toBlob(blob => {
          this.downloadLoading = false
          if (blob) {
            this.triggerDownload(URL.createObjectURL(blob), `${this.activeTab}.png`)
            this.$message.success('PNG 已下载')
          }
        }, 'image/png')
      }
      img.onerror = () => {
        this.downloadLoading = false
        this.$message.error('PNG 导出失败')
      }
      img.src = url
    },
    triggerDownload(url, filename) {
      const a = document.createElement('a')
      a.href = url
      a.download = filename
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)
    },
    switchTab(key) {
      this.activeTab = key
      this.selectedNode = null
    },
    bindNodeEvents() {
      const el = this.$refs.diagram
      if (!el) return
      const svg = el.querySelector('svg')
      if (!svg) return
      const groups = svg.querySelectorAll('g:not([class*="edge"])')
      groups.forEach(g => {
        const hasRect = g.querySelector('rect, path, ellipse, polygon')
        const text = g.querySelector('text, span')
        if (hasRect && text) {
          g.style.cursor = 'pointer'
        }
      })
    },
    onNodeClick(e) {
      let target = e.target
      while (target && target !== e.currentTarget) {
        if (target.tagName === 'g') {
          const textEl = target.querySelector('text, span')
          if (textEl) {
            const label = textEl.textContent.replace(/\s+/g, ' ').trim()
            if (label) {
              this.selectedNode = label
              this.$message({ message: label, type: 'info', duration: 1500 })
              return
            }
          }
        }
        target = target.parentElement
      }
    },
  },
}
</script>

<style scoped>
.flow-page {
  padding: 0;
}

.flow-tabs {
  display: flex;
  gap: 4px;
  padding: 8px 12px;
  background: #fafafa;
  border-bottom: 1px solid #e8e8e8;
}

.flow-tab-item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 16px;
  font-size: 13px;
  color: #606266;
  cursor: pointer;
  border-radius: 4px;
  transition: all 0.2s ease;
  white-space: nowrap;
  user-select: none;
}

.flow-tab-item:hover {
  color: #409eff;
  background: rgba(64, 158, 255, 0.06);
}

.flow-tab-item.active {
  color: #409eff;
  background: #e6f0fd;
}

.flow-tab-item i {
  font-size: 13px;
}

.flow-content {
  min-height: 480px;
  background: #fff;
  overflow: auto;
}

.flow-diagram {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px;
}

.flow-diagram :deep(svg) {
  max-width: 100%;
  height: auto;
}

.flow-diagram :deep(svg g) {
  transition: opacity 0.15s ease;
}

.flow-diagram :deep(svg g:hover) {
  opacity: 0.8;
}

.flow-toolbar {
  display: flex;
  justify-content: flex-end;
  padding: 6px 12px;
  background: #fafafa;
  border-bottom: 1px solid #e8e8e8;
}
</style>
