<template>
  <div class="home">
    <div class="map" id="map"></div>
    <div class="left-part">
      <el-card>
        <template #header>
          <div class="custom-title">
            <img src="@/assets/images/title.svg" />
            <span>本月</span>
          </div>
        </template>
        <BaseChart width="100%" height="100%" :option="barOptions" />
      </el-card>
      <el-card style="margin-top: 10px">
        <template #header>
          <div class="custom-title">
            <img src="@/assets/images/title.svg" />
            <span>本周</span>
          </div>
        </template>
        <div class="card-subtitle">
          <span></span>
          <span>一级</span>
        </div>
        <div class="custom-card">
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '1').length }}</span>
            <span>所有数量</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '1' && item.status == '1').length }}</span>
            <span>已解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '1' && (item.status == '2' || item.status === null)).length }}</span>
            <span>未解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '1' && item.status == '3').length }}</span>
            <span>已上报</span>
          </div>
        </div>
        <div class="card-subtitle">
          <span style="background: #efc439"></span>
          <span>二级</span>
        </div>
        <div class="custom-card">
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '2').length }}</span>
            <span>所有数量</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '2' && item.status == '1').length }}</span>
            <span>已解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '2' && (item.status == '2' || item.status === null)).length }}</span>
            <span>未解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '2' && item.status == '3').length }}</span>
            <span>已上报</span>
          </div>
        </div>
        <div class="card-subtitle">
          <span style="background: #1890ff"></span>
          <span>三级</span>
        </div>
        <div class="custom-card">
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '3').length }}</span>
            <span>所有数量</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '3' && item.status == '1').length }}</span>
            <span>已解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '3' && (item.status == '2' || item.status === null)).length }}</span>
            <span>未解决</span>
          </div>
          <div class="card-item">
            <span>{{ statData.weekData.filter((item) => item.level == '3' && item.status == '3').length }}</span>
            <span>已上报</span>
          </div>
        </div>
      </el-card>
      <el-card style="margin-top: 10px">
        <template #header>
          <div class="custom-title">
            <img src="@/assets/images/title.svg" />
            <span>统计分析</span>
          </div>
        </template>
        <BaseChart width="100%" height="100%" :option="pieOptions" />
      </el-card>
    </div>
    <div class="expandOrFold" :style="{ 'right': showList ? '550px' : '0' }" @click="showList = !showList">
      <img v-if="showList" src="@/assets/images/fold.svg" alt="" />
      <img v-else src="@/assets/images/expand.svg" alt="" />
    </div>
    <div class="right-part" v-show="showList">
      <div class="event-title">
        <div>
          <el-select style="width: 100px" v-model="queryParams.level" clearable placeholder="事件等级">
            <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
          </el-select>
          <el-select style="width: 100px; margin-left: 10px" v-model="queryParams.params.lx" filterable clearable placeholder="事件类型">
            <el-option v-for="dict in eventTypeOptions" :key="dict" :label="dict" :value="dict"></el-option>
          </el-select>
          <el-date-picker
            v-model="queryParams.dateRange"
            style="margin-left: 10px"
            type="daterange"
            unlink-panels
            range-separator="～"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :shortcuts="shortcuts"
            value-format="YYYY-MM-DD HH:mm:ss"
          />
        </div>
        <div style="margin-top: 10px">
          <el-select style="width: 210px" v-model="queryParams.params.deviceId" clearable placeholder="设备">
            <el-option v-for="dict in deviceList" :key="dict.name" :label="dict.name" :value="dict.id"></el-option>
          </el-select>
          <el-input v-model="queryParams.params.key" style="margin-left: 10px; width: 165px" placeholder="输入地点关键词" :suffix-icon="Search" />
          <div style="margin-left: 10px">
            <el-button color="#1890FF" style="color: #fff" @click="getList">查询</el-button>
            <el-button @click="resetQuery">重置</el-button>
          </div>
        </div>
      </div>
      <div class="event-list">
        <el-table :data="eventList" :border="false" :header-cell-style="{ background: '#fff!important' }" style="width: 100%">
          <el-table-column prop="level" label="事件等级" width="80" align="center">
            <template #default="{ row }">
              <!-- {{ event_level.filter((item) => item.value == row.level)[0]?.label }} -->
              <span class="span-label" v-if="row.level == 1">一级</span>
              <span class="span-label" v-else-if="row.level == 2" style="background: #ed923c">二级</span>
              <span class="span-label" v-else-if="row.level == 3" style="background: #3cbbed">三级</span>
              <span v-else>{{ event_level.filter((item) => item.value == row.level)[0]?.label }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="ext2.lx" label="事件类型" show-overflow-tooltip width="100" align="center" />
          <el-table-column prop="addr" label="发生地点" show-overflow-tooltip align="center" />
          <el-table-column prop="createTimeFormat" label="发生时间" width="100" align="center" />
          <el-table-column prop="status" label="状态" width="70" align="center">
            <template #default="{ row }">
              <span v-if="row.status == 3" style="color: #5f86fd">已上报</span>
              <span v-else-if="row.status == 1" style="color: #26c768">已解决</span>
              <span v-else-if="row.status == 2" style="color: #ff6124">未解决</span>
              <span v-else>{{ event_status.filter((item) => item.value == row.status)[0]?.label }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="60" align="center">
            <template #default="{ row }">
              <el-button link type="primary" @click="showDetails(row)">查看</el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="event-footer">
        <pagination
          background
          layout="prev, pager, next"
          v-show="total > 0"
          :total="total"
          v-model:page="queryParams.pageNum"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </div>
    </div>
    <el-dialog v-model="dialog.visible" :title="dialogTitle" width="1000px" top="5vh" append-to-body @close="dialogClose">
      <!-- <template #header>
        <span style="font-weight: 500; font-size: 16px">事件详情</span>
        <div style="display: flex; justify-content: space-between; align-items: center; padding-right: 30px">
          <span>事件详情</span>
          <el-button @click="saveClick">保存</el-button>
        </div>
      </template> -->
      <div class="dialog-loading-warp">
        <div class="steps">
          <div v-for="item in 4" :key="item" :class="{ 'step-item': true, 'step-selected': curStep >= item }">
            <span @click="stepClick(item)">{{ item }}</span>
            <p v-if="(item == 2 && firstHtml != '') || (item == 4 && valueHtml != '')">报告已生成</p>
          </div>
        </div>
        <div v-show="curStep == 1">
          <el-form ref="addFormRef" :model="form" label-position="top" label-width="90px" label-suffix=":">
            <el-row :gutter="20">
              <el-col :span="8">
                <el-form-item label="事件ID" prop="id">
                  <el-input v-model="form.id" placeholder="请输入" readonly />
                </el-form-item>
              </el-col>
              <el-col :span="8">
                <el-form-item label="事件类型" prop="ext2.lx">
                  <el-select v-model="form.ext2.lx" clearable filterable allow-create placeholder="请选择" @change="formSubmit('lx', 'ext2')">
                    <el-option v-for="dict in eventTypeOptions" :key="dict" :label="dict" :value="dict"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="8">
                <el-form-item label="发生时间" prop="createTime">
                  <el-date-picker
                    style="width: 100%"
                    v-model="form.createTime"
                    value-format="YYYY-MM-DD HH:mm:ss"
                    @change="formSubmit('createTime')"
                    type="date"
                    placeholder="请选择"
                  />
                </el-form-item>
              </el-col>
              <el-col :span="8">
                <el-form-item label="事件等级" prop="level">
                  <el-select v-model="form.level" clearable placeholder="请选择" @change="formSubmit('level')">
                    <el-option v-for="dict in event_level" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="8">
                <el-form-item label="桩号" prop="ext2.zh">
                  <el-input v-model="form.ext2.zh" placeholder="请输入" @blur="formSubmit('zh', 'ext2')" />
                </el-form-item>
              </el-col>
              <el-col :span="8">
                <el-form-item label="状态" prop="status">
                  <el-select v-model="form.status" clearable placeholder="请选择" @change="formSubmit('status')">
                    <el-option v-for="dict in event_status" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-form-item label="地点描述" prop="addr">
                  <el-input v-model="form.addr" type="textarea" placeholder="请输入" @blur="formSubmit('addr')" />
                </el-form-item>
              </el-col>
            </el-row>
          </el-form>
          <div class="event-media" v-if="form.imgList && form.imgList.length">
            <div class="event-media-title">现场画面</div>
            <div class="event-media-content">
              <div class="imgs">
                <el-image v-for="item in form.imgList" :key="item" :src="item" show-progress :preview-src-list="form.imgList" fit="cover" />
              </div>
            </div>
          </div>
          <div class="event-media" v-if="form.videoList && form.videoList.length" style="margin-top: 10px">
            <div class="event-media-title">现场视频</div>
            <div class="event-media-content">
              <div class="videos">
                <div v-for="(item, index) in form.videoList" :key="index" :id="`player${index}`"></div>
              </div>
            </div>
          </div>
        </div>
        <template v-if="curStep == 2">
          <div class="report-editor">
            <div class="report-title">报告内容：</div>
            <div style="border: 1px solid #d9d9d9; margin-top: 10px">
              <Editor style="height: 420px; overflow-y: hidden" v-model="firstHtml" :defaultConfig="editorConfig" @onCreated="handleFirstCreated" />
            </div>
          </div>
        </template>
        <template v-else-if="curStep == 3">
          <div class="event-media">
            <div class="event-media-title">需核验信息</div>
            <div class="event-media-content" v-html="verifyInfo"></div>
          </div>
          <div class="verif-info">
            <template v-for="(item, index) in form.ext2.reports" :key="index">
              <div class="verif-title">
                <div>部门选择：</div>
                <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px">
                  <el-select style="width: 240px" v-model="item.dept" clearable placeholder="请选择">
                    <el-option v-for="dict in event_dept" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
                  </el-select>
                  <el-button v-if="index == 0" class="borderRad0" @click="addEventDepts" type="primary" color="#1890FF">新增</el-button>
                  <el-button v-else class="borderRad0 delBtn" @click="delEventDepts(index)">删除</el-button>
                </div>
              </div>
              <el-input v-model="item.content" style="margin-top: 10px" :rows="3" type="textarea" placeholder="请填写核验信息" />
            </template>
          </div>
        </template>
        <template v-else-if="curStep == 4">
          <div class="report-editor">
            <div class="report-title">报告内容：</div>
            <div style="border: 1px solid #d9d9d9; margin-top: 10px">
              <Editor style="height: 420px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" @onCreated="handleCreated" />
            </div>
          </div>
          <div style="margin-top: 20px">
            <div class="report-title">格式选择：</div>
            <div style="display: flex; align-items: center; margin-top: 10px">
              <el-select v-model="reportForm.type" clearable placeholder="请选择">
                <el-option label="pdf" value="pdf"></el-option>
                <el-option label="word" value="docx"></el-option>
              </el-select>
              <el-button color="#2AB55C" style="color: #fff; margin-left: 10px" @click="dialogVisible = true">导出报告</el-button>
            </div>
          </div>
        </template>
      </div>
      <template #footer>
        <div class="report-btn">
          <img v-show="curStep == 1" @click="generateClick" src="@/assets/images/report.svg" alt="" />
          <el-button color="#1890FF" class="borderRad0" type="primary" @click="lastStep" v-show="curStep > 1">上一步</el-button>
          <el-button color="#1890FF" class="borderRad0" type="primary" @click="nextStep" v-show="curStep > 1 && curStep < 4">下一步</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="dialogVisible" title="导出信息" width="500">
      <el-form ref="reportFormRef" :model="reportForm" label-width="90px" label-suffix=":">
        <el-row :gutter="20">
          <el-col :span="24">
            <el-form-item label="期数" prop="seq" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.seq" placeholder="请输入" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="发送范围" prop="fw" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.fw" placeholder="请输入" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="备案号" prop="ba" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.ba" placeholder="请输入" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="值班员" prop="zby" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.zby" placeholder="请输入" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="审核" prop="sh" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.sh" placeholder="请输入" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="签发" prop="qf" :rules="[{ required: true, message: '请输入', trigger: 'blur' }]">
              <el-input v-model="reportForm.qf" placeholder="请输入" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" :loading="downLoading" @click="htmlToPdfFn">确 认</el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="showVideo" title="实时视频" width="600" @close="closeVideo" append-to-body>
      <div id="mse" class="real-video"></div>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { Search } from '@element-plus/icons-vue';
import BaseChart from '@/components/BaseChart/index.vue';
import monitorIcon from '@/assets/images/monitor.svg';
import monitorEventIcon from '@/assets/images/monitor-event.svg';
import Player from 'xgplayer';
import 'xgplayer/dist/index.min.css';
import HlsPlugin from 'xgplayer-hls';
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import { downloadFile } from '@/utils/download.js';
import { listEvent, generateReport, updateEvent, getEvent, getEventTypes } from '@/api/system/event';
import { listDevice, getHlsCode, closeHlsCode } from '@/api/system/device';
import { listData } from '@/api/system/dict/data';
import { dateFormat } from '@/utils/index';
import { ElLoading, ElNotification } from 'element-plus';
import { base64Encoded, base64Decoded } from '@/utils/crypto';
const { proxy } = getCurrentInstance();
const bdmap = ref(null);
const downLoading = ref(false);
const { event_level } = toRefs(proxy?.useDict('event_level'));
const { event_status } = toRefs(proxy?.useDict('event_status'));
const { event_dept } = toRefs(proxy?.useDict('event_dept'));
const firstEditorRef = shallowRef();
const editorRef = shallowRef();
const editorConfig = { placeholder: '请输入内容...' };
// 内容 HTML
const firstHtml = ref('');
const valueHtml = ref('');
const handleFirstCreated = (editor) => {
  firstEditorRef.value = editor;
};
const handleCreated = (editor) => {
  editorRef.value = editor;
};
const showReport = ref(false);
const reportFormRef = ref(null);
const reportTime = ref('');
const queryParams = ref({
  pageNum: 1,
  pageSize: 15,
  level: undefined,
  dateRange: undefined,
  params: {
    lx: undefined,
    key: undefined,
    deviceId: undefined,
    beginCreateTime: '',
    endCreateTime: ''
  }
});
const dialogTitle = computed(() => {
  if (curStep.value == 2 || curStep.value == 4) return '生成报告';
  if (curStep.value == 3) return '现场核验';
  return '事件详情';
});
const dialog = reactive({
  visible: false,
  title: '事件详情',
  loading: null
});
const form = ref<any>({});
const statData = reactive({
  monthCount: undefined,
  monthAlready: undefined,
  monthNot: undefined,
  monthReport: undefined,
  monthRemove: undefined,
  weekData: [],
  dayCount: undefined,
  dayAlready: undefined,
  dayNot: undefined,
  dayReport: undefined,
  already: undefined,
  not: undefined,
  report: undefined
});
const showList = ref(true);
const showVideo = ref(false);
const curVideoUrl = ref('');
const shortcuts = [
  {
    text: '最近一周',
    value: () => {
      const end = new Date();
      const start = new Date();
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
      return [start, end];
    }
  },
  {
    text: '最近一个月',
    value: () => {
      const end = new Date();
      const start = new Date();
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
      return [start, end];
    }
  },
  {
    text: '最近三个月',
    value: () => {
      const end = new Date();
      const start = new Date();
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
      return [start, end];
    }
  }
];
const barOptions = computed(() => {
  return {
    grid: {
      containLabel: true,
      top: '10%',
      right: '3%',
      bottom: '3%',
      left: '0%'
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      }
    },
    xAxis: {
      type: 'category',
      axisTick: {
        show: false
      },
      axisLine: {
        show: true,
        lineStyle: {
          color: '#cfcfcf'
        }
      },
      axisLabel: {
        show: true,
        color: '#666'
      },
      splitLine: {
        // show: false
      },
      data: event_status.value.map((item) => item.label)
    },
    yAxis: {
      type: 'value',
      min: 0,
      minInterval: 1
    },
    series: [
      {
        type: 'bar',
        barWidth: 15,
        data: [
          {
            value: statData.monthAlready,
            itemStyle: {
              color: '#46CE76'
            }
          },
          {
            value: statData.monthNot,
            itemStyle: {
              color: '#F36060'
            }
          },
          {
            value: statData.monthReport,
            itemStyle: {
              color: '#5DC4FB'
            }
          },
          {
            value: statData.monthRemove,
            itemStyle: {
              color: '#EFC439'
            }
          }
        ]
      }
    ]
  };
});
const pieOptions = computed(() => {
  const options = {
    tooltip: {
      trigger: 'item'
    },
    legend: {
      orient: 'horizontal',
      left: 'center',
      itemWidth: 15,
      itemHeight: 8,
      itemGap: 10
    },
    series: [
      {
        type: 'pie',
        radius: ['40%', '80%'],
        center: ['50%', '60%'],
        data: [
          {
            value: statData.already,
            name: '已解决',
            itemStyle: {
              color: '#FAC858'
            }
          },
          {
            value: statData.not,
            name: '未解决',
            itemStyle: {
              color: '#93BEFF'
            }
          },
          {
            value: statData.report,
            name: '已上报',
            itemStyle: {
              color: '#507AFC'
            }
          }
        ],
        labelLine: {
          show: false
        },
        label: {
          show: false,
          position: 'center'
        }
      }
    ]
  };
  return options;
});
const eventList = ref([]);
const total = ref(0);
const dialogVisible = ref(false);
const reportForm = reactive({
  'year': null,
  'seq': 1,
  'title': '',
  'month': null,
  'day': null,
  'content': '',
  'fw': '市委、市政府总值班室',
  'qf': '宗仁',
  'sh': '朱劲',
  'ps': '',
  'ba': 'KB608',
  'zby': '83194295',
  'tpl': 'sg.docx',
  'type': 'pdf'
});
const reportSeq = ref(0);
const deviceList = ref([]);
const hasEventDevices = ref([]);
const eventTypeOptions = ref([]);
const videoPlayer = ref(null);
const curStep = ref(1);
const eventVerifOptions = ref([]);
const verifyInfo = ref('');
const POLL_INTERVAL = 30000; // 30秒
let pollTimer = null;
onMounted(() => {
  try {
    const map = new BMapGL.Map('map'); // 创建地图实例
    const point = new BMapGL.Point(118.879999, 32.016216); // 创建点坐标
    map.centerAndZoom(point, 14);
    map.enableScrollWheelZoom(true);
    map.setTrafficOn();
    bdmap.value = map;
    map.addEventListener('click', function (e) {
      const { lng, lat } = e.latlng;
      console.log(e.latlng);
    });
  } catch (e) {}
  getEventTypeOptions();
  getEventVerifOptions();
  getList('init');
  getStat();
  getDeviceList();
  // 设置轮询
  pollTimer = setInterval(() => {
    getList('init');
  }, POLL_INTERVAL);
});
onUnmounted(() => {
  clearInterval(pollTimer);
});
const getEventVerifOptions = () => {
  listData({
    pageNum: 1,
    pageSize: 100,
    dictName: '',
    dictType: 'event_verification',
    dictLabel: ''
  }).then(({ code, rows }) => {
    if (code == 200) {
      eventVerifOptions.value = rows;
    }
  });
};
const getEventTypeOptions = () => {
  getEventTypes().then(({ code, data }) => {
    if (code === 200) {
      eventTypeOptions.value = data;
    }
  });
};
const getList = async (type) => {
  if (type == 'init') {
    queryParams.value.pageNum = 1;
  }
  const { dateRange } = queryParams.value;
  if (dateRange && dateRange.length) {
    queryParams.value.params.beginCreateTime = dateRange[0];
    queryParams.value.params.endCreateTime = dateRange[1];
  } else {
    queryParams.value.params.beginCreateTime = undefined;
    queryParams.value.params.endCreateTime = undefined;
  }
  const res = await listEvent(queryParams.value);
  // 创建新列表（带格式化）
  const newList = res.rows.map((item) => ({
    ...item,
    status: item.status || '2',
    createTimeFormat: dateFormat(new Date(item.createTime), 'yyyy-MM-dd'),
    ext1: item.ext1 ? JSON.parse(item.ext1) : [],
    ext2: item.ext2 ? JSON.parse(item.ext2) : {}
  }));

  // 检测新事件（只在已有数据时检测）
  if (eventList.value.length > 0) {
    const newEvents = detectNewEvents(eventList.value, newList);
    if (newEvents.length > 0) {
      showNewEventNotification(newEvents);
    }
  }
  // 更新列表引用
  eventList.value = newList;
  total.value = res.total;
};
const detectNewEvents = (oldList, newList) => {
  const oldIds = new Set(oldList.map((item) => item.id));
  return newList.filter((item) => !oldIds.has(item.id));
};
// 辅助函数：显示新事件通知
const showNewEventNotification = (newEvents) => {
  const count = newEvents.length;
  const eventText = count > 1 ? `产生${count}个新事件` : '产生1个新事件';
  ElNotification({
    title: '提示',
    message: eventText,
    type: 'warning'
  });
};
const getStat = async () => {
  const monthRange = getTimeRange('month');
  const monthRes = await listEvent({
    params: {
      beginCreateTime: monthRange.start,
      endCreateTime: monthRange.end
    }
  });
  statData.monthCount = monthRes.total;
  statData.monthAlready = monthRes.rows.filter((item) => item.status == '1').length;
  statData.monthNot = monthRes.rows.filter((item) => item.status == '2' || item.status === null).length;
  statData.monthReport = monthRes.rows.filter((item) => item.status == '3').length;
  statData.monthRemove = monthRes.rows.filter((item) => item.status == '4').length;
  const weekRange = getTimeRange('week', { firstDayOfWeek: 0 });
  const weekRes = await listEvent({
    params: {
      beginCreateTime: weekRange.start,
      endCreateTime: weekRange.end
    }
  });
  statData.weekData = weekRes.rows;
  const todayRange = getTimeRange('day');
  const todayRes = await listEvent({
    params: {
      beginCreateTime: todayRange.start,
      endCreateTime: todayRange.end
    }
  });
  statData.dayCount = todayRes.total;
  statData.dayAlready = todayRes.rows.filter((item) => item.status == '1').length;
  statData.dayNot = todayRes.rows.filter((item) => item.status == '2' || item.status === null).length;
  statData.dayReport = todayRes.rows.filter((item) => item.status == '3').length;
  const res = await listEvent({});
  statData.already = res.rows.filter((item) => item.status == '1').length;
  statData.not = res.rows.filter((item) => item.status == '2' || item.status === null).length;
  statData.report = res.rows.filter((item) => item.status == '3').length;
};
const getTimeRange = (unit = 'day', options: any = {}) => {
  const now = new Date();
  const { firstDayOfWeek = 1 } = options;

  // 定义结果容器
  const result = {
    unit,
    startDate: null,
    endDate: null,
    start: '',
    end: '',
    description: '',
    duration: 0
  };

  // 内部工具函数：格式化日期时间为字符串
  const format = (date) => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  };

  // 处理不同类型的时间范围
  switch (unit.toLowerCase()) {
    case 'day':
      // 当天范围 (00:00:00.000 - 23:59:59.999)
      const dayStart = new Date(now);
      dayStart.setHours(0, 0, 0, 0);

      const dayEnd = new Date(now);
      dayEnd.setHours(23, 59, 59, 999);

      result.startDate = dayStart;
      result.endDate = dayEnd;
      result.start = format(dayStart);
      result.end = format(dayEnd);
      result.description = `当天范围: ${result.start} 至 ${result.end}`;
      result.duration = 1;
      break;

    case 'week':
      // 计算周起始日偏移
      const dayOfWeek = now.getDay();
      const diffToFirstDay = (dayOfWeek < firstDayOfWeek ? 7 : 0) + dayOfWeek - firstDayOfWeek;

      // 本周开始 (周一 00:00:00.000)
      const weekStart = new Date(now);
      weekStart.setDate(now.getDate() - diffToFirstDay);
      weekStart.setHours(0, 0, 0, 0);

      // 本周结束 (周日 23:59:59.999)
      const weekEnd = new Date(weekStart);
      weekEnd.setDate(weekStart.getDate() + 6);
      weekEnd.setHours(23, 59, 59, 999);

      // 设置结果
      result.startDate = weekStart;
      result.endDate = weekEnd;
      result.start = format(weekStart);
      result.end = format(weekEnd);
      result.duration = 7;

      // 生成描述信息
      const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
      const startDayName = weekDays[firstDayOfWeek];
      const endDayName = weekDays[(firstDayOfWeek + 6) % 7];
      result.description = `本周范围 (${startDayName}至${endDayName}): ${result.start} 至 ${result.end}`;
      break;

    case 'month':
      // 本月第一天 (1号 00:00:00.000)
      const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
      monthStart.setHours(0, 0, 0, 0);

      // 本月最后一天 (月末日 23:59:59.999)
      const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);
      monthEnd.setHours(23, 59, 59, 999);

      // 设置结果
      result.startDate = monthStart;
      result.endDate = monthEnd;
      result.start = format(monthStart);
      result.end = format(monthEnd);

      // 计算天数
      const dayDiff = Math.floor((monthEnd - monthStart) / (1000 * 60 * 60 * 24)) + 1;
      result.duration = dayDiff;

      // 获取月份名称
      const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
      result.description = `${monthNames[now.getMonth()]}范围 (共${dayDiff}天): ${result.start} 至 ${result.end}`;
      break;

    default:
      throw new Error(`无效的时间单位: "${unit}". 请使用 'day', 'week' 或 'month'`);
  }

  return result;
};
const resetQuery = () => {
  queryParams.value = {
    pageNum: 1,
    pageSize: 15,
    level: undefined,
    dateRange: undefined,
    params: {
      lx: undefined,
      key: undefined,
      deviceId: undefined,
      beginCreateTime: '',
      endCreateTime: ''
    }
  };
  getList('init');
};
const getDeviceList = () => {
  listDevice({}).then(async ({ code, rows }) => {
    if (code === 200) {
      await getHasEventDeviceList();
      deviceList.value = rows.map((item) => {
        let hasEvent = 0;
        if (hasEventDevices.value.some((el) => el.id == item.id)) {
          hasEvent = 1;
        }
        return {
          ...item,
          ext1: item.ext1 && JSON.parse(item.ext1),
          hasEvent
        };
      });
      showMarks();
    }
  });
};
const getHasEventDeviceList = async () => {
  await listDevice({ params: { hasevent: '1' } }).then(({ code, rows }) => {
    if (code === 200) {
      hasEventDevices.value = rows;
    }
  });
};
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
const showMarks = () => {
  bdmap.value.clearOverlays();
  deviceList.value
    .filter((item) => item.lon && item.lat)
    .forEach((item) => {
      const pt = new BMapGL.Point(Number(item.lon), Number(item.lat));
      const img = item.hasEvent == 1 ? monitorEventIcon : monitorIcon;
      const icon = new BMapGL.Icon(img, new BMapGL.Size(30, 30));
      const marker = new BMapGL.Marker(pt, { icon });
      marker.addEventListener('click', (e) => {
        if (item.ext1 && item.ext1.streamUrl) {
          showVideoDialog(item.ext1.streamUrl);
        } else {
          proxy?.$modal.msgError('暂未配置视频流地址');
        }
        if (item.hasEvent == 1) {
          queryParams.value.params.deviceId = item.id;
          queryParams.value.pageNum = 1;
          getList('init');
        }
      });
      bdmap.value.addOverlay(marker);
    });
};
const showVideoDialog = (url) => {
  curVideoUrl.value = url;
  showVideo.value = true;
  let realUrl = '';
  getHlsCode(base64Encoded(url)).then(({ code, data }) => {
    if (code == 200) {
      if (import.meta.env.DEV) {
        realUrl = data.replace(/^http:\/\/jtjai\.xt\.wenhq\.top:8083/, '');
      } else {
        realUrl = data;
      }

      if (HlsPlugin.isSupported()) {
        videoPlayer.value = new Player({
          id: 'mse',
          url: realUrl,
          isLive: false,
          autoplay: true,
          plugins: [HlsPlugin],
          ignores: ['cssfullscreen'],
          hls: {
            retryCount: 3, // 重试 3 次，默认值
            retryDelay: 1000, // 每次重试间隔 1 秒，默认值
            loadTimeout: 10000, // 请求超时时间为 10 秒，默认值
            fetchOptions: {
              // 该参数会透传给 fetch，默认值为 undefined
              mode: 'cors'
            }
          }
        });
      }
    }
  });
};
const closeVideo = () => {
  if (curVideoUrl.value) {
    closeHlsCode(base64Encoded(curVideoUrl.value));
    videoPlayer.value.destroy();
    videoPlayer.value = null;
  }
};
const showDetails = async (row) => {
  curStep.value = 1;
  if (row.status == null || row.status == '2') {
    await updateEvent({ id: row.id, status: '1' });
    getList('init');
  }
  getEvent(row.id).then(({ code, data }) => {
    if (code === 200) {
      data.ext1 = JSON.parse(data.ext1) || [];
      data.ext2 = JSON.parse(data.ext2) || {};
      data.ext2.reports = data.ext2.reports || [
        {
          dept: '',
          content: ''
        }
      ];
      let imgList = [];
      let videoList = [];
      if (data.ext1.length) {
        videoList = data.ext1
          .filter((item) => item.includes('mp4'))
          .map((item) => `${import.meta.env.VITE_APP_BASE_HOST}/api/oss/local/upload/${item}`);
        imgList = data.ext1
          .filter((item) => !item.includes('mp4'))
          .map((item) => `${import.meta.env.VITE_APP_BASE_HOST}/api/oss/local/upload/${item}`);
      }
      if (data.ext2.EventVideoPath) {
        videoList = [data.ext2.EventVideoPath];
      }

      form.value = data;
      Object.assign(form.value, { imgList, videoList });
      dialog.visible = true;
      nextTick(() => {
        form.value.videoList.forEach((item, index) => {
          new Player({
            el: document.getElementById(`player${index}`),
            url: item
          });
        });
      });
      verifyInfo.value = '';
      const verifyIndex = eventVerifOptions.value.findIndex((item) => form.value.ext2.lx.includes(item.dictValue));
      if (verifyIndex > -1) {
        verifyInfo.value = eventVerifOptions.value[verifyIndex].remark.replace(/\n/g, '<br>');
      }
      const { content, ext2 } = form.value;
      if (ext2.firstContent && base64Decoded(ext2.firstContent)) {
        firstHtml.value = base64Decoded(ext2.firstContent);
      }
      if (content && base64Decoded(content) && ext2.reportTime) {
        dealReportData(base64Decoded(content), ext2.reportTime);
      }
    }
  });
};

const generateClick = () => {
  if (dialog.loading) return;
  dialog.loading = ElLoading.service({
    lock: true,
    text: '正在生成AI报告...',
    fullscreen: false,
    target: '.dialog-loading-warp',
    background: 'rgba(255, 255, 255, 0.6)'
  });
  generateReport(form.value.id, curStep.value == 1 ? 1 : null).then(async ({ code, msg }) => {
    dialog.loading.close();
    dialog.loading = null;
    if (code == 200 && msg) {
      const { report, time } = JSON.parse(msg).data.outputs;
      const reportHtml = report.replace(/```/g, '').replace(/html\n/, '');
      if (curStep.value == 1) {
        firstHtml.value = reportHtml;
      } else if (curStep.value == 3) {
        const { reports, ...rest } = form.value.ext2;
        const params = {
          id: form.value.id,
          ext2: ''
        };
        const reportDeptArr = reports.filter((item) => item.dept != '');
        if (reportDeptArr.length > 0) {
          params.ext2 = JSON.stringify({
            ...form.value.ext2,
            reportTime: time,
            reports: reportDeptArr
          });
        } else {
          params.ext2 = JSON.stringify({
            ...rest,
            reportTime: time
          });
        }
        reportTime.value = time;
        valueHtml.value = reportHtml;
        updateEvent({
          ...params,
          content: base64Encoded(reportHtml)
        });
        dealReportData(reportHtml, time);
      }
      curStep.value++;
      proxy?.$modal.msgSuccess('报告生成成功');
    } else {
      proxy?.$modal.msgError('报告生成失败');
    }
  });
};
const saveClick = async () => {
  const { ext2, createTime, level, status, addr } = form.value;
  const params = {
    id: form.value.id,
    createTime,
    level,
    status,
    addr,
    ext2: JSON.stringify({
      ...ext2
    })
  };
  if (showReport.value) {
    let htmlcontent = '';
    const text = editorRef.value.getText();
    if (text) {
      htmlcontent = editorRef.value.getHtml();
    }
    await updateEvent({
      ...params,
      content: base64Encoded(htmlcontent),
      ext2: JSON.stringify({
        ...ext2,
        reportTime: reportTime.value
      })
    });
  } else {
    await updateEvent(params);
  }
  getList('init');
  getStat();
  getEventTypeOptions();
  getDeviceList();
  proxy?.$modal.msgSuccess('保存成功');
};
const extractDate = (dateStr) => {
  // 统一处理两种格式的正则表达式
  const match = dateStr.match(/(\d{4})[^\d]*(\d{1,2})[^\d]*(\d{1,2})/);

  if (!match) return null;

  return {
    year: parseInt(match[1]),
    month: parseInt(match[2]),
    day: parseInt(match[3])
  };
};
const dealReportData = async (reportHtml, time) => {
  const res = await proxy?.getConfigKey('report_seq');
  reportSeq.value = Number(res.data);
  valueHtml.value = reportHtml;
  const { year, month, day } = extractDate(time);
  reportForm.year = year;
  reportForm.month = month;
  reportForm.day = day;
  reportForm.seq = reportSeq.value;
};
const extractTitleAndContents = (htmlString) => {
  // 提取标题（从 <h2><strong> 中获取）
  const titleMatch = htmlString.match(/<h2[^>]*>.*?<strong>(.*?)<\/strong>.*?<\/h2>/is);
  const title = titleMatch ? titleMatch[1].trim() : '';

  // 提取所有 <p> 内容（从 <p><span> 中获取）
  const contentMatches = [...htmlString.matchAll(/<p[^>]*>.*?<span[^>]*>(.*?)<\/span>.*?<\/p>/gis)];
  const contents = contentMatches.map((match) => match[1].trim());

  return {
    title,
    contents
  };
};
const htmlToPdfFn = async () => {
  reportFormRef.value.validate((valid) => {
    if (valid) {
      downLoading.value = true;
      const { title, contents } = extractTitleAndContents(editorRef.value.getHtml());
      reportForm.title = title;
      reportForm.content = contents.join('');
      //import.meta.env.VITE_APP_ENV === 'development' ? 'loadFile/generate' :
      let url = `${import.meta.env.VITE_APP_BASE_HOST}/generate`;
      if (import.meta.env.DEV) {
        url = 'loadFile/generate';
      }
      downloadFile(url, {
        method: 'POST',
        data: reportForm,
        filename: `${reportForm.title}.${reportForm.type}`,
        onProgress: (percent) => {
          console.log(percent);
          if (percent == 100) {
            downLoading.value = false;
            proxy?.updateConfigByKey('report_seq', reportSeq.value + 1);
            if (form.value.status != '3') {
              form.value.status = '3';
              updateEvent({ id: form.value.id, status: '3' });
            }
            proxy?.$modal.msgSuccess('报告导出成功');
            dialogVisible.value = false;
          }
        }
      });
    }
  });
};
const dialogClose = () => {
  showReport.value = false;
  dialog.loading && dialog.loading.close();
};
const formSubmit = async (field, obj = '') => {
  const { id } = form.value;
  const params = {
    id
  };
  if (obj) {
    params[obj] = form.value[obj];
    params[obj] = JSON.stringify(params[obj]);
  } else {
    params[field] = form.value[field];
  }
  await updateEvent(params);
  getList('init');
  if (field === 'status') {
    getStat();
  }
  if (field === 'ext2.lx') {
    getEventTypeOptions();
  }
};
const stepClick = (item) => {
  if (firstHtml.value == '') return;
  if (item == 4 && valueHtml.value == '') return;
  curStep.value = item;
};
const lastStep = () => {
  if (dialog.loading) return;
  curStep.value--;
};
const nextStep = () => {
  if (dialog.loading) return;
  const params = {
    id: form.value.id,
    ext2: ''
  };
  const { reports, ...rest } = form.value.ext2;
  if (curStep.value == 2) {
    let htmlcontent = '';
    const text = firstEditorRef.value.getText();
    if (text) {
      htmlcontent = firstEditorRef.value.getHtml();
    }
    let reportDeptFlag = true;
    if (reports.filter((item) => item.dept != '').length == 0) {
      reportDeptFlag = false;
    }
    reportDeptFlag
      ? (params.ext2 = JSON.stringify({
          ...form.value.ext2,
          firstContent: base64Encoded(htmlcontent)
        }))
      : (params.ext2 = JSON.stringify({
          ...rest,
          firstContent: base64Encoded(htmlcontent)
        }));
    updateEvent(params);
    curStep.value++;
  } else if (curStep.value == 3) {
    generateClick();
  }
};
const addEventDepts = () => {
  form.value.ext2.reports.push({
    dept: '',
    content: ''
  });
};
const delEventDepts = (index) => {
  form.value.ext2.reports.splice(index, 1);
};
</script>
<style lang="scss" scoped>
.home {
  height: 100%;
  background-color: #f0f2f5;
  position: relative;

  .left-part {
    position: absolute;
    width: 300px;
    top: 10px;
    left: 20px;
    bottom: 10px;
    z-index: 10;
    display: flex;
    flex-direction: column;

    > .el-card:first-child {
      height: 24%;

      :deep(.el-card__body) {
        height: 70%;
      }
    }

    > .el-card:nth-child(2) {
      flex: 1;

      :deep(.el-card__body) {
        height: 80%;
        overflow-y: auto;
      }
    }

    > .el-card:last-child {
      height: 32%;

      :deep(.el-card__body) {
        height: 80%;
      }
    }
  }

  .right-part {
    position: absolute;
    background: #fff;
    border-radius: 4px;
    top: 0;
    width: 550px;
    right: 0;
    bottom: 0px;
    z-index: 10;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
    display: flex;
    flex-direction: column;
  }

  .expandOrFold {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    right: 550px;
    cursor: pointer;
    z-index: 10;

    img {
      height: 50px;
    }
  }
}

.custom-title {
  display: flex;
  align-items: center;
  color: #000000;
  font-size: 16px;

  img {
    height: 16px;
    margin-right: 5px;
  }
}

.card-subtitle {
  color: #000000d9;
  font-size: 14px;
  padding: 8px 0;

  &:not(:first-child) {
    margin-top: 10px;
  }

  span:first-child {
    display: inline-block;
    width: 12px;
    height: 12px;
    opacity: 1;
    background: #f36060;
    border-radius: 50%;
    margin-right: 5px;
  }
}

.custom-card {
  display: flex;
  justify-content: space-between;
  height: 72px;

  .card-item {
    display: flex;
    width: 22.5%;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100%;
    background: #e3eefe;
    color: #2d5794;
    border-radius: 4.8px;

    span:first-child {
      flex: 1;
      font-size: 22px;
      margin-top: 10px;
      display: flex;
      align-items: center;
    }

    span:last-child {
      width: 80%;
      text-align: center;
      height: 26px;
      line-height: 26px;
      border-top: 0.6px solid #d0dff4;
      font-size: 10px;
    }
  }
}

.week-card {
  .card-item {
    background: #fef4e3;

    span:first-child {
      color: #7c5b22;
    }

    span:last-child {
      border-color: #eddbbc;
      color: #8c692e;
    }
  }
}

.day-card {
  .card-item {
    background: #e3fef0;

    span:first-child {
      color: #248647;
    }

    span:last-child {
      border-color: #ade7cd;
      color: #238546;
    }
  }
}

.map {
  width: 100%;
  height: 100%;
}

.event-title {
  flex-shrink: 0;
  padding: 10px;
  background: linear-gradient(180deg, #ffffff 0%, #f5f5f5 100%);
  border-radius: 4px 4px 0 0;

  > div {
    display: flex;
    align-items: center;

    > .el-select {
      flex-shrink: 0;
    }
  }
}

.steps {
  display: flex;
  justify-content: center;
  padding: 20px 0;
  .step-item {
    position: relative;
    p {
      position: absolute;
      top: 25px;
      left: -10px;
      color: #1890ff;
      font-size: 12px;
      width: 100px;
    }
    span {
      width: 35px;
      height: 35px;
      display: flex;
      justify-content: center;
      align-items: center;
      border: 2px solid #1890ff;
      color: #1890ff;
      font-size: 20px;
      font-weight: 700;
      border-radius: 50%;
      cursor: pointer;
    }
    &:not(:last-child) {
      display: flex;
      align-items: center;

      &::after {
        content: '';
        width: 100px;
        height: 0;
        margin: 0 20px;
        border: 0.5px solid #a6a6a6;
      }
    }
  }
  // > div {
  //   // position: relative;
  //   // p {
  //   //   position: absolute;
  //   //   left: 0;
  //   // }

  // }
  // > div > div

  .step-selected span {
    background: #1890ff;
    color: #ffffff;
  }
}

.event-list {
  flex: 1;
  overflow-y: auto;

  :deep() {
    .el-table__cell {
      border: none;
    }
  }
}

.event-footer {
  height: 60px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding-right: 20px;

  .pagination-container {
    margin-top: 0;
  }

  :deep() {
    .el-pagination.is-background .btn-next,
    .el-pagination.is-background .btn-prev,
    .el-pagination.is-background .el-pager li {
      background: transparent;
      border: 1px solid #00000026;
      color: #000000a6;
    }

    .el-pagination.is-background .is-active {
      background: #1890ff !important;
      border: none !important;
      color: #fff !important;
      font-weight: normal;
    }
  }
}

.event-media {
  border: 1px solid #f0f0f0;

  &-title {
    background: #fbfbfb;
    padding: 10px;
    font-size: 14px;
    color: #000000;
    border-bottom: 1px solid #f0f0f0;
  }

  &-content {
    padding: 20px;

    .imgs {
      display: flex;
      flex-wrap: wrap;

      .el-image {
        height: 100px;
        width: 100px;
        margin-right: 10px;
        border-radius: 4px;
        margin-top: 10px;
      }
    }

    .videos {
      display: flex;
      flex-wrap: wrap;

      div {
        height: 200px !important;
        width: 32% !important;
        border-radius: 4px;
        margin-right: 10px;
        margin-top: 10px;
      }
    }
  }
}

.report-btn {
  height: 52px;
  line-height: 52px;

  img {
    height: 52px;
    cursor: pointer;
  }
}

.hidden-report {
  position: absolute;
  visibility: hidden;
  left: -9999px;
  top: -9999px;
  width: max-content;
  height: max-content;
  display: inline-block;
  contain: layout;
}

.report-content {
  width: 800px;
  height: auto;
  padding: 20px;
  background-color: #fff;
  border: 1px solid #eee;
}

.report-editor {
  margin-top: 20px;
}

.report-title {
  color: #5d5d5dd9;
  font-size: 14px;
}

.real-video {
  height: 400px !important;
  width: 100% !important;
}

.borderRad0 {
  border-radius: 0;
}

.verif-info {
  .verif-title {
    margin-top: 15px;
    color: #5d5d5dd9;
    font-size: 14px;
  }
}

.delBtn {
  border: 1px solid #ff3d3d;
  color: #ff3d3d;

  &:active {
    background-color: #fff;
  }
}

.span-label {
  border-radius: 5px;
  opacity: 1;
  background: #ed3c3c;
  color: #fff;
  padding: 2px 5px;
  font-size: 14px;
}
</style>
