<template>
  <div class="NCC-common-layout attendance-record-page" v-loading="pageLoading">
    <div class="NCC-common-layout-center">
      <div class="NCC-common-layout-main NCC-flex-main page-shell">
        <el-card class="filter-card" shadow="never">
          <el-form :inline="true" :model="query" class="filter-form" @submit.native.prevent>
            <el-form-item label="视图">
              <el-radio-group v-model="viewMode" size="mini" @change="onViewModeChange">
                <el-radio-button label="month">月</el-radio-button>
                <el-radio-button label="week">周</el-radio-button>
              </el-radio-group>
            </el-form-item>

            <el-form-item v-if="viewMode === 'month'" label="统计月份">
              <el-date-picker v-model="query.month" type="month" value-format="yyyy-MM" format="yyyy-MM"
                placeholder="选择月份" />
            </el-form-item>
            <el-form-item v-else label="选择日期">
              <el-date-picker v-model="query.weekDate" type="date" value-format="yyyy-MM-dd" format="yyyy-MM-dd"
                placeholder="选择任意日期" @change="onWeekDateChange" />
            </el-form-item>
            <el-form-item label="考勤分组">
              <el-select v-model="query.attendanceGroupId" clearable filterable placeholder="全部分组">
                <el-option v-for="item in attendanceGroupOptions" :key="item.id" :label="item.fullName"
                  :value="item.id" />
              </el-select>
            </el-form-item>
            <el-form-item label="关键字">
              <el-input v-model.trim="query.keyword" clearable placeholder="员工 / 门店 / 分组" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="el-icon-search" @click="search">查询</el-button>
              <el-button icon="el-icon-refresh-right" @click="resetQuery">重置</el-button>
              <el-button icon="el-icon-refresh-right" @click="refreshPage">刷新</el-button>
              <el-button v-if="viewMode === 'month'" type="primary" plain icon="el-icon-download" :loading="exportLoading"
                @click="exportMonthReport">导出月度明细</el-button>
            </el-form-item>
          </el-form>
        </el-card>

        <el-card class="table-card" shadow="never">
          <div slot="header" class="table-card__header">
            <div>
              <span>{{ viewMode === 'month' ? '月度考勤明细' : '周度考勤明细' }}</span>
              <span class="table-card__sub">{{ headerText }}</span>
            </div>
            <div class="table-card__legend">
              <span class="legend-item"><i class="dot success"></i>正常</span>
              <span class="legend-item"><i class="dot warning"></i>迟到</span>
              <span class="legend-item"><i class="dot info"></i>休息/无记录</span>
              <span class="legend-item"><i class="dot danger"></i>请假 / 缺卡 / 旷工</span>
            </div>
          </div>

          <div class="table-card__body-inner">
            <div class="table-card__table-wrap">
              <NCC-table v-show="tableLoading || tableRows.length" v-loading="tableLoading" :data="tableRows" border
                size="mini" height="100%" :hasNO="false" class="record-table">
                <el-table-column prop="employeeName" label="员工姓名" fixed="left" min-width="140" align="left" />
                <el-table-column prop="storeName" label="门店" fixed="left" min-width="120" align="left" />
                <el-table-column prop="groupName" label="当月考勤组" fixed="left" min-width="140" align="left" show-overflow-tooltip />
                <el-table-column label="月统计" fixed="left" min-width="180" align="left">
                  <template slot-scope="scope">
                    <div class="month-stat">
                      <span>正常 {{ scope.row.monthStats.normal }}</span>
                      <span>迟到 {{ scope.row.monthStats.late }}</span>
                      <span>异常 {{ scope.row.monthStats.abnormal }}</span>
                    </div>
                  </template>
                </el-table-column>

                <el-table-column v-for="day in activeDays" :key="day.key" :label="day.label" :min-width="110" align="left">
                  <template slot-scope="scope">
                    <div class="day-cell"
                      :class="[`status-${scope.row.dayRecords[day.key].statusKey}`, 'clickable']"
                      @click="handleOpenDetail(scope.row, day.key, scope.row.dayRecords[day.key])">
                      <div class="day-cell__time">{{ scope.row.dayRecords[day.key].timeText }}</div>
                      <el-tag :type="scope.row.dayRecords[day.key].tagType" size="mini" effect="plain">
                        {{ scope.row.dayRecords[day.key].statusText }}
                      </el-tag>
                    </div>
                  </template>
                </el-table-column>
              </NCC-table>

              <div v-show="!tableLoading && !tableRows.length" class="empty-wrap">
                <el-empty :image-size="68" description="当前筛选条件下暂无数据" />
              </div>
            </div>

            <div v-show="showPagination" class="table-card__pager">
              <Pagination
                :total="paginationTotal"
                :page.sync="query.currentPage"
                :limit.sync="query.pageSize"
                :hide-on-single-page="false"
                layout="total, sizes, prev, pager, next, jumper"
                @pagination="onPagination"
              />
            </div>
          </div>
        </el-card>

        <record-detail-dialog ref="recordDetailDialog" @refresh="loadData" />
      </div>
    </div>
  </div>
</template>

<script>
import dayjs from 'dayjs'
import { getAttendanceGroupSelector } from '@/api/extend/attendanceSetting'
import { saveAs } from 'file-saver'
import { getAttendanceMonthReport, exportAttendanceMonthReport } from '@/api/extend/attendanceRecord'
import Pagination from '@/components/Pagination'
import RecordDetailDialog from './components/record-detail-dialog.vue'

export default {
  name: 'AttendanceRecordPage',
  components: {
    Pagination,
    RecordDetailDialog
  },
  data() {
    return {
      viewMode: 'month',
      pageLoading: false,
      tableLoading: false,
      exportLoading: false,
      query: this.createDefaultQuery(),
      attendanceGroupOptions: [],
      tableRows: [],
      total: 0
    }
  },
  computed: {
    /** 月视图需选月份；周视图按周日期展示分页（月份由 loadData 同步写入，不单独依赖 query.month 显示） */
    showPagination() {
      if (this.viewMode === 'month') return !!this.query.month
      return !!this.query.weekDate
    },
    paginationTotal() {
      const n = Number(this.total)
      return Number.isFinite(n) && n >= 0 ? n : 0
    },
    headerText() {
      if (this.viewMode === 'week') {
        const anchor = dayjs(this.query.weekDate || dayjs().format('YYYY-MM-DD'))
        const diff = (anchor.day() + 6) % 7 // Monday-based
        const start = anchor.subtract(diff, 'day')
        const end = start.add(6, 'day')
        return `${start.format('YYYY-MM-DD')} ~ ${end.format('YYYY-MM-DD')}`
      }
      return `${this.query.month} · 共 ${this.activeDays.length} 天`
    },
    activeDays() {
      if (this.viewMode === 'week') {
        const anchor = dayjs(this.query.weekDate || dayjs().format('YYYY-MM-DD'))
        const diff = (anchor.day() + 6) % 7 // Monday-based
        const start = anchor.subtract(diff, 'day')
        return Array.from({ length: 7 }).map((_, index) => {
          const date = start.add(index, 'day')
          return {
            key: date.format('YYYY-MM-DD'),
            label: `${index + 1}日\n${this.getWeekLabel(date.day())}`
          }
        })
      }
      const base = dayjs(`${this.query.month}-01`)
      const total = base.daysInMonth()
      return Array.from({ length: total }).map((_, index) => {
        const date = base.date(index + 1)
        return {
          key: date.format('YYYY-MM-DD'),
          label: `${index + 1}日\n${this.getWeekLabel(date.day())}`
        }
      })
    }
  },
  created() {
    this.initPage()
  },
  methods: {
    createDefaultQuery() {
      return {
        month: dayjs().format('YYYY-MM'),
        weekDate: dayjs().format('YYYY-MM-DD'),
        attendanceGroupId: '',
        keyword: '',
        currentPage: 1,
        pageSize: 10
      }
    },
    createEmptyDayRecord() {
      return {
        statusKey: 'empty',
        statusText: '无',
        tagType: 'info',
        timeText: '--'
      }
    },
    async initPage() {
      this.pageLoading = true
      try {
        const groupRes = await getAttendanceGroupSelector().catch(() => ({ data: { list: [] } }))
        this.attendanceGroupOptions = groupRes.data.list || []
        await this.loadData()
      } finally {
        this.pageLoading = false
      }
    },
    async exportMonthReport() {
      if (!this.query.month) {
        this.$message.warning('请先选择统计月份')
        return
      }
      this.exportLoading = true
      try {
        const blob = await exportAttendanceMonthReport({
          month: this.query.month,
          attendanceGroupId: this.query.attendanceGroupId || '',
          keyword: this.query.keyword || ''
        })
        const fileName = `考勤记录_${this.query.month}.xlsx`
        saveAs(
          new Blob([blob], {
            type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
          }),
          fileName
        )
        this.$message.success('导出成功')
      } catch (e) {
        this.$message.error((e && e.message) || '导出失败')
      } finally {
        this.exportLoading = false
      }
    },
    async loadData() {
      if (this.viewMode === 'week') {
        this.query.month = dayjs(this.query.weekDate || dayjs().format('YYYY-MM-DD')).format('YYYY-MM')
      }
      if (!this.query.month) {
        this.total = 0
        this.tableRows = []
        this.tableLoading = false
        return
      }
      this.tableLoading = true
      try {
        const res = await getAttendanceMonthReport(this.query)
        const data = this.unwrapMonthReportPayload(res)
        const pageInfo = data.pagination || data.Pagination || {}
        let t = pageInfo.total != null ? pageInfo.total : pageInfo.Total
        if (t == null && typeof pageInfo === 'object') {
          t = pageInfo.totalCount != null ? pageInfo.totalCount : pageInfo.TotalCount
        }
        this.total = t != null ? Number(t) : 0
        const list = data.list || data.List || []
        this.tableRows = list.map(item => this.normalizeRow(item))
      } catch (error) {
        this.total = 0
        this.tableRows = []
      } finally {
        this.tableLoading = false
      }
    },
    onPagination() {
      this.loadData()
    },
    /** 兼容统一封装 { code, data } 及 camelCase / PascalCase */
    unwrapMonthReportPayload(res) {
      if (!res || typeof res !== 'object') return {}
      let inner = res.data != null ? res.data : res
      if (inner && typeof inner === 'object' && inner.data != null && (inner.data.list != null || inner.data.List != null)) {
        inner = inner.data
      }
      return inner && typeof inner === 'object' ? inner : {}
    },
    normalizeRow(item) {
      const dayRecordMap = {}
      this.activeDays.forEach(day => {
        dayRecordMap[day.key] = this.createEmptyDayRecord()
      })
        ; (item.dayRecords || []).forEach(record => {
          dayRecordMap[record.date] = {
            ...this.createEmptyDayRecord(),
            ...record
          }
        })
      return {
        ...item,
        monthStats: item.monthStats || { normal: 0, late: 0, abnormal: 0 },
        dayRecords: dayRecordMap
      }
    },
    refreshPage() {
      this.loadData()
    },
    search() {
      if (this.viewMode === 'month' && !this.query.month) {
        this.$message.warning('请选择统计月份')
        return
      }
      if (this.viewMode === 'week' && !this.query.weekDate) {
        this.$message.warning('请选择日期')
        return
      }
      this.query.currentPage = 1
      this.loadData()
    },
    onViewModeChange() {
      this.query.currentPage = 1
      this.loadData()
    },
    onWeekDateChange() {
      this.query.currentPage = 1
      this.loadData()
    },
    resetQuery() {
      this.query = this.createDefaultQuery()
      this.loadData()
    },
    handleOpenDetail(row, attendanceDate, dayRecord) {
      // 即使当天为“空白/无记录”，也允许点开详情（弹窗内会显示暂无详情）
      this.$refs.recordDetailDialog.open({
        userId: row.userId,
        attendanceDate
      })
    },
    getWeekLabel(day) {
      return ['日', '一', '二', '三', '四', '五', '六'][day]
    }
  }
}
</script>

<style lang="scss" scoped>
.attendance-record-page {
  background: #f5f7fb;

  /* 主内容区默认 overflow:hidden；配合 min-height:0 与表格卡片 flex 占满剩余高度，底部分页常驻可见 */
  &.NCC-common-layout .NCC-common-layout-main.NCC-flex-main {
    overflow-x: hidden;
    overflow-y: auto;
    min-height: 0;
  }

  /* 与 .NCC-flex-main 同节点：占满 center 剩余高度，才能把 flex:1 传到表格卡片 */
  .page-shell {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    gap: 12px;
  }

  .filter-card {
    flex-shrink: 0;
  }

  /* 占满主列剩余高度，避免表格用 100vh 把分页顶出可视区或被父级 overflow 裁切 */
  .table-card.el-card {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }

  .table-card ::v-deep .el-card__header {
    flex-shrink: 0;
    padding: 14px 18px;
  }

  .table-card ::v-deep .el-card__body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 12px 14px;
  }

  .table-card__body-inner {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
  }

  /* 全局 common.scss 中 .NCC-flex-main .el-table { flex:1 } 会破坏 height:100% 计算；此处用绝对定位占满剩余区域 */
  .table-card__table-wrap {
    flex: 1;
    min-height: 200px;
    overflow: hidden;
    position: relative;
  }

  .table-card__table-wrap ::v-deep .el-table {
    position: absolute !important;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    flex: none !important;
    width: auto !important;
  }

  .table-card__pager {
    flex-shrink: 0;
    padding: 10px 4px 2px;
    margin: 0;
    border-top: 1px solid #ebeef5;
    background: #fafbfc;
    position: relative;
    z-index: 3;
  }

  .table-card__pager ::v-deep .pagination-container {
    margin-top: 0;
    padding: 0;
    text-align: right;
  }

  .table-card__pager ::v-deep .el-pagination {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 8px 0;
    width: 100%;
    padding: 4px 0;
  }

  .filter-card,
  .table-card {
    border-radius: 14px;
    border: 1px solid #ebeef5;
  }

  .filter-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 0;
  }

  .table-card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    font-weight: 600;
  }

  .table-card__sub {
    margin-left: 10px;
    color: #909399;
    font-size: 12px;
    font-weight: 400;
  }

  .table-card__legend {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    color: #606266;
    font-size: 12px;
    font-weight: 400;
  }

  .legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }

  .dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #909399;
  }

  .dot.success {
    background: #67c23a;
  }

  .dot.warning {
    background: #e6a23c;
  }

  .dot.info {
    background: #909399;
  }

  .dot.danger {
    background: #f56c6c;
  }

  .month-stat {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: #606266;
    font-size: 12px;
    line-height: 1.5;
  }

  .day-cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 54px;
    padding: 4px 0;
  }

  .day-cell.clickable {
    cursor: pointer;
  }

  .day-cell.clickable:hover {
    transform: translateY(-1px);
  }

  .day-cell__time {
    color: #303133;
    font-size: 12px;
    line-height: 1.4;
    white-space: nowrap;
  }

  .status-normal .day-cell__time {
    color: #1f8f43;
  }

  .status-late .day-cell__time {
    color: #c67a10;
  }

  .status-leave .day-cell__time,
  .status-sick .day-cell__time,
  .status-missing .day-cell__time,
  .status-absenteeism .day-cell__time {
    color: #d93f3f;
  }

  .status-rest .day-cell__time,
  .status-empty .day-cell__time,
  .status-pending .day-cell__time {
    color: #909399;
  }

  .record-table {
    ::v-deep .el-table__header-wrapper th {
      background: #f8fbff;
      color: #303133;
      font-weight: 600;
      vertical-align: top;
    }

    ::v-deep .el-table__header-wrapper th .cell {
      white-space: pre-line;
      line-height: 1.3;
    }

    ::v-deep .el-table__body td {
      vertical-align: top;
    }
  }

  .empty-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px 0;
  }

  @media (max-width: 768px) {
    .table-card__header {
      flex-direction: column;
      align-items: flex-start;
    }
  }
}
</style>
