NoPhotoStats.vue 10.2 KB
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { Search, Download } from '@element-plus/icons-vue'
import * as echarts from 'echarts'
import { statsApi } from '../../api'
import type { ApiResponse } from '../../types/order'

// 获取昨天的日期范围
const getYesterdayRange = () => {
  const yesterday = new Date()
  yesterday.setDate(yesterday.getDate() - 1)
  yesterday.setHours(0, 0, 0, 0)
  const start = new Date(yesterday)
  
  const end = new Date(yesterday)
  end.setHours(23, 59, 59, 999)
  
  return [start, end]
}

// 格式化日期时间为 yyyy-MM-dd HH:mm:ss
const formatDateTime = (date: Date): string => {
  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}`
}

const queryForm = reactive({
    dateRange: getYesterdayRange() as any[],
    city: ''
})

const loading = ref(false)

const cities = [
    { code: '3201', name: '南京市' },
    { code: '3202', name: '无锡市' },
    { code: '3203', name: '徐州市' },
    { code: '3204', name: '常州市' },
    { code: '3205', name: '苏州市' },
    { code: '3206', name: '南通市' },
    { code: '3207', name: '连云港市' },
    { code: '3208', name: '淮安市' },
    { code: '3209', name: '盐城市' },
    { code: '3210', name: '扬州市' },
    { code: '3211', name: '镇江市' },
    { code: '3212', name: '泰州市' },
    { code: '3213', name: '宿迁市' }
]

const cityTableData = ref<any[]>([])
const deviceTableData = ref<any[]>([])

const chartRef = ref<HTMLElement>()
let chart: echarts.ECharts | null = null

// 获取地市统计数据
const fetchCityStats = async () => {
  loading.value = true
  
  try {
    const params: any = {}
    
    // 处理日期范围
    if (queryForm.dateRange && queryForm.dateRange.length === 2) {
      const start = queryForm.dateRange[0]
      const end = queryForm.dateRange[1]
      if (start && end) {
        params.startDate = formatDateTime(new Date(start))
        
        // 设置结束时间为当天的 23:59:59
        const endDate = new Date(end)
        endDate.setHours(23, 59, 59, 999)
        params.endDate = formatDateTime(endDate)
      }
    }
    
    // 处理地市选择
    if (queryForm.city) {
      params.areaType = queryForm.city
    }
    
    const response = await statsApi.getNoShowCityStatistics(params) as ApiResponse<any>
    
    if (response.code === 200 || response.code === 0) {
      cityTableData.value = response.data || []
      updateChart()
    }
  } catch (error) {
    console.error('获取地市统计数据失败:', error)
  } finally {
    loading.value = false
  }
}

// 获取设备统计数据
const fetchDeviceStats = async () => {
  try {
    const params: any = {}
    
    // 处理日期范围
    if (queryForm.dateRange && queryForm.dateRange.length === 2) {
      const start = queryForm.dateRange[0]
      const end = queryForm.dateRange[1]
      if (start && end) {
        params.startDate = formatDateTime(new Date(start))
        
        // 设置结束时间为当天的 23:59:59
        const endDate = new Date(end)
        endDate.setHours(23, 59, 59, 999)
        params.endDate = formatDateTime(endDate)
      }
    }
    
    // 处理地市选择
    if (queryForm.city) {
      params.areaType = queryForm.city
    }
    
    const response = await statsApi.getNoShowProcessStatistics(params) as ApiResponse<any>
    
    if (response.code === 200 || response.code === 0) {
      deviceTableData.value = response.data || []
    }
  } catch (error) {
    console.error('获取设备统计数据失败:', error)
  }
}

// 更新图表
const updateChart = () => {
    if (chartRef.value && cityTableData.value.length > 0) {
        if (!chart) {
            chart = echarts.init(chartRef.value)
        }
        
        const cityNames = cityTableData.value.map(item => item.areaName)
        const count1Data = cityTableData.value.map(item => item.percentage1 || 0)
        const count2Data = cityTableData.value.map(item => item.percentage2 || 0)
        const count3Data = cityTableData.value.map(item => item.percentage3 || 0)
        
        chart.setOption({
            title: { text: '地市不能拍次数占比统计' },
            tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
            legend: { data: ['1次', '2次', '3次'], bottom: 0 },
            grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
            xAxis: { 
                type: 'category', 
                data: cityNames, 
                axisLabel: { interval: 0, rotate: 30 } 
            },
            yAxis: { type: 'value', name: '占比%' },
            series: [
                { name: '1次', type: 'bar', data: count1Data },
                { name: '2次', type: 'bar', data: count2Data },
                { name: '3次', type: 'bar', data: count3Data }
            ]
        })
    }
}

// 查询
const handleSearch = () => {
    fetchCityStats()
    fetchDeviceStats()
}

// 导出地市统计
const handleExportCity = async () => {
  try {
    const params: any = {}
    
    // 处理日期范围
    if (queryForm.dateRange && queryForm.dateRange.length === 2) {
      const start = queryForm.dateRange[0]
      const end = queryForm.dateRange[1]
      if (start && end) {
        params.startDate = formatDateTime(new Date(start))
        
        // 设置结束时间为当天的 23:59:59
        const endDate = new Date(end)
        endDate.setHours(23, 59, 59, 999)
        params.endDate = formatDateTime(endDate)
      }
    }
    
    // 处理地市选择
    if (queryForm.city) {
      params.areaType = queryForm.city
    }
    
    const blob = await statsApi.exportNoShowGoupByAreaType(params)
    
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `地市不能拍次数统计_${new Date().toISOString().split('T')[0]}.xlsx`
    
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  } catch (error) {
    console.error('导出地市统计失败:', error)
  }
}

// 导出设备统计
const handleExportDevice = async () => {
  try {
    const params: any = {}
    
    // 处理日期范围
    if (queryForm.dateRange && queryForm.dateRange.length === 2) {
      const start = queryForm.dateRange[0]
      const end = queryForm.dateRange[1]
      if (start && end) {
        params.startDate = formatDateTime(new Date(start))
        
        // 设置结束时间为当天的 23:59:59
        const endDate = new Date(end)
        endDate.setHours(23, 59, 59, 999)
        params.endDate = formatDateTime(endDate)
      }
    }
    
    const blob = await statsApi.exportNoShowProcessStatistics(params)
    
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = `设备不能拍次数统计_${new Date().toISOString().split('T')[0]}.xlsx`
    
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
  } catch (error) {
    console.error('导出设备统计失败:', error)
  }
}

onMounted(() => {
    fetchCityStats()
    fetchDeviceStats()
})
</script>

<template>
  <div class="nophoto-stats-page" v-loading="loading">
     <!-- Filter -->
    <el-card shadow="never" class="mb-4">
      <el-form :inline="true" :model="queryForm">
        <el-form-item label="日期">
           <el-date-picker
            v-model="queryForm.dateRange"
            type="datetimerange"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
          />
        </el-form-item>
        <el-form-item label="地区">
            <el-select v-model="queryForm.city" placeholder="请选择" class="!w-40" clearable>
                <el-option v-for="c in cities" :key="c.code" :label="c.name" :value="c.code" />
            </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- Chart -->
    <el-card shadow="never" class="mb-4">
        <div ref="chartRef" style="height: 400px"></div>
    </el-card>

    <!-- Tables -->
    <div class="grid grid-cols-1 gap-4">
        <el-card shadow="never">
            <template #header>
                <div class="flex justify-between">
                    <span class="font-bold">地市不能拍次数统计</span>
                    <el-button link type="primary" :icon="Download" @click="handleExportCity">导出</el-button>
                </div>
            </template>
            <el-table :data="cityTableData" border stripe>
                <el-table-column prop="areaName" label="地市" />
                <el-table-column label="1次不能拍">
                    <template #default="{row}">{{row.count1}} ({{row.percentage1}}%)</template>
                </el-table-column>
                <el-table-column label="2次不能拍">
                    <template #default="{row}">{{row.count2}} ({{row.percentage2}}%)</template>
                </el-table-column>
                <el-table-column label="3次不能拍">
                    <template #default="{row}">{{row.count3}} ({{row.percentage3}}%)</template>
                </el-table-column>
            </el-table>
        </el-card>

        <el-card shadow="never">
             <template #header>
                <div class="flex justify-between">
                    <span class="font-bold">设备不能拍次数统计</span>
                    <el-button link type="primary" :icon="Download" @click="handleExportDevice">导出</el-button>
                </div>
            </template>
             <el-table :data="deviceTableData" border stripe>
                <el-table-column prop="processName" label="设备名称" />
                <el-table-column prop="noShowCount" label="不能拍总次数" sortable />
            </el-table>
        </el-card>
    </div>
  </div>
</template>