<template>
  <div class="audit-page">
    <div class="page-header">
      <div class="page-title-group">
        <h1 class="page-title">审计日志</h1>
        <span class="page-subtitle">记录所有用户操作，支持追溯与问责</span>
      </div>
      <button class="export-btn" @click="handleExport" :disabled="exporting">
        {{ exporting ? '导出中…' : '导出 CSV' }}
      </button>
    </div>

    <!-- 筛选栏 -->
    <div class="filter-bar">
      <el-date-picker
        v-model="dateRange"
        type="datetimerange"
        range-separator="至"
        start-placeholder="开始时间"
        end-placeholder="结束时间"
        size="small"
        style="width: 340px"
        @change="onFilter"
      />
      <el-input v-model="filters.username" placeholder="用户名" size="small" style="width: 130px" clearable @change="onFilter" />
      <el-select v-model="filters.action_type" placeholder="操作类型" size="small" style="width: 120px" clearable @change="onFilter">
        <el-option v-for="t in actionTypes" :key="t.value" :label="t.label" :value="t.value" />
      </el-select>
      <el-select v-model="filters.status" placeholder="状态" size="small" style="width: 100px" clearable @change="onFilter">
        <el-option label="成功" value="success" />
        <el-option label="失败" value="failed" />
        <el-option label="错误" value="error" />
      </el-select>
      <button class="reset-btn" @click="resetFilters">重置</button>
    </div>

    <!-- 表格 -->
    <div class="table-wrap">
      <el-table :data="logs" size="small" style="width:100%" v-loading="loading" @row-click="openDetail">
        <el-table-column label="时间" width="160">
          <template #default="{ row }">
            <span class="mono-val">{{ fmtTime(row.action_time) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="用户" width="110">
          <template #default="{ row }">
            <span>{{ row.username }}</span>
            <span class="role-tag">{{ row.user_role }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="90">
          <template #default="{ row }">
            <span :class="['type-tag', `type-${row.action_type}`]">{{ typeLabel(row.action_type) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="子类型" width="80">
          <template #default="{ row }">
            <span class="muted">{{ row.action_subtype || '—' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="描述" min-width="180" show-overflow-tooltip prop="description" />
        <el-table-column label="路径" min-width="200" show-overflow-tooltip>
          <template #default="{ row }">
            <span class="mono-val small">{{ row.request_method }} {{ row.request_path }}</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="72" align="center">
          <template #default="{ row }">
            <span :class="['status-dot', `status-${row.status}`]">{{ statusLabel(row.status) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="IP" width="130">
          <template #default="{ row }">
            <span class="mono-val small">{{ row.ip_address || '—' }}</span>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination">
        <el-pagination
          v-model:current-page="page"
          v-model:page-size="pageSize"
          :total="total"
          :page-sizes="[20, 50, 100]"
          layout="total, sizes, prev, pager, next"
          size="small"
          @change="fetchLogs"
        />
      </div>
    </div>

    <!-- 详情抽屉 -->
    <el-drawer v-model="drawerVisible" title="日志详情" size="480px" direction="rtl">
      <div v-if="detail" class="detail-body">
        <div class="detail-row" v-for="(v, k) in detailFields" :key="k">
          <span class="detail-label">{{ v.label }}</span>
          <span class="detail-value" :class="{ mono: v.mono }">{{ v.val }}</span>
        </div>
        <template v-if="detail.request_params">
          <div class="detail-section">请求参数</div>
          <pre class="json-block">{{ JSON.stringify(detail.request_params, null, 2) }}</pre>
        </template>
        <template v-if="detail.error_message">
          <div class="detail-section">错误信息</div>
          <pre class="json-block error">{{ detail.error_message }}</pre>
        </template>
      </div>
    </el-drawer>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { ElMessage } from '../utils/message'
import { getAuditLogs, getAuditLogDetail, exportAuditLogs } from '../api/audit'
import { fmtTime } from '../utils/datetime'

const logs = ref([])
const total = ref(0)
const page = ref(1)
const pageSize = ref(50)
const loading = ref(false)
const exporting = ref(false)
const drawerVisible = ref(false)
const detail = ref(null)
const dateRange = ref(null)

const filters = ref({ username: '', action_type: '', status: '' })

const actionTypes = [
  { label: '认证', value: 'auth' },
  { label: '设备', value: 'device' },
  { label: 'OLT', value: 'olt' },
  { label: '用户', value: 'user' },
  { label: '系统', value: 'system' },
  { label: '库存', value: 'inventory' },
]

const typeLabel = (t) => actionTypes.find(x => x.value === t)?.label || t
const statusLabel = (s) => ({ success: '成功', failed: '失败', error: '错误' }[s] || s)
// fmtTime 从 utils/datetime 导入，已在文件顶部

const buildParams = () => {
  const p = { page: page.value, page_size: pageSize.value }
  if (dateRange.value?.[0]) p.start_time = dateRange.value[0].toISOString()
  if (dateRange.value?.[1]) p.end_time = dateRange.value[1].toISOString()
  if (filters.value.username) p.username = filters.value.username
  if (filters.value.action_type) p.action_type = filters.value.action_type
  if (filters.value.status) p.status = filters.value.status
  return p
}

const fetchLogs = async () => {
  loading.value = true
  try {
    const { data } = await getAuditLogs(buildParams())
    logs.value = data.items
    total.value = data.total
  } catch {
    ElMessage.error('加载失败')
  } finally {
    loading.value = false
  }
}

const onFilter = () => { page.value = 1; fetchLogs() }
const resetFilters = () => {
  filters.value = { username: '', action_type: '', status: '' }
  dateRange.value = null
  page.value = 1
  fetchLogs()
}

const openDetail = async (row) => {
  try {
    const { data } = await getAuditLogDetail(row.id)
    detail.value = data
    drawerVisible.value = true
  } catch { ElMessage.error('加载详情失败') }
}

const detailFields = computed(() => {
  if (!detail.value) return {}
  const d = detail.value
  return {
    time:    { label: '时间',   val: fmtTime(d.action_time), mono: true },
    user:    { label: '用户',   val: `${d.username} (${d.user_role})` },
    type:    { label: '操作',   val: `${typeLabel(d.action_type)} / ${d.action_subtype || '—'}` },
    path:    { label: '路径',   val: `${d.request_method} ${d.request_path}`, mono: true },
    status:  { label: '状态',   val: `${statusLabel(d.status)} (${d.status_code})` },
    ip:      { label: 'IP',     val: d.ip_address || '—', mono: true },
    desc:    { label: '描述',   val: d.description },
    ua:      { label: 'UA',     val: d.user_agent || '—' },
  }
})

const handleExport = async () => {
  exporting.value = true
  try {
    const { data } = await exportAuditLogs(buildParams())
    const url = URL.createObjectURL(new Blob([data]))
    const a = document.createElement('a')
    a.href = url
    a.download = `audit_${Date.now()}.csv`
    a.click()
    URL.revokeObjectURL(url)
  } catch { ElMessage.error('导出失败') } finally { exporting.value = false }
}

onMounted(fetchLogs)
</script>

<style scoped>
.audit-page { padding: 24px; }
.page-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 20px; }
.page-title-group { display: flex; flex-direction: column; gap: 4px; }
.page-title { margin: 0; font-size: 22px; font-weight: 700; color: var(--text-primary); letter-spacing: -0.02em; }
.page-subtitle { font-size: 12px; color: var(--text-muted); }
.export-btn { padding: 7px 16px; background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: var(--radius-sm); color: var(--text-secondary); font-size: 13px; cursor: pointer; }
.export-btn:hover { border-color: var(--accent); color: var(--accent); }
.filter-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; align-items: center; }
.reset-btn { padding: 6px 12px; background: transparent; border: 1px solid var(--border-default); border-radius: var(--radius-sm); color: var(--text-muted); font-size: 12px; cursor: pointer; }
.reset-btn:hover { color: var(--text-primary); }
.table-wrap { background: var(--bg-card); border: 1px solid var(--border-default); border-radius: var(--radius-lg); overflow: hidden; }
.pagination { padding: 12px 16px; display: flex; justify-content: flex-end; border-top: 1px solid var(--border-subtle); }
.mono-val { font-family: var(--font-mono); font-size: 12px; }
.small { font-size: 11px; }
.muted { color: var(--text-muted); font-size: 12px; }
.role-tag { margin-left: 4px; font-size: 10px; color: var(--text-muted); background: var(--bg-elevated); padding: 1px 5px; border-radius: 3px; }
.type-tag { font-size: 11px; padding: 2px 7px; border-radius: 3px; font-weight: 500; }
.type-auth     { background: #dbeafe; color: #1d4ed8; }
.type-device   { background: #dcfce7; color: #15803d; }
.type-olt      { background: #fef9c3; color: #854d0e; }
.type-user     { background: #fce7f3; color: #9d174d; }
.type-system   { background: #f3e8ff; color: #6b21a8; }
.type-inventory{ background: #ffedd5; color: #9a3412; }
.status-dot { font-size: 11px; padding: 2px 7px; border-radius: 3px; }
.status-success { background: #dcfce7; color: #15803d; }
.status-failed  { background: #fef9c3; color: #854d0e; }
.status-error   { background: #fee2e2; color: #991b1b; }
.detail-body { padding: 4px 0; }
.detail-row { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border-subtle); font-size: 13px; }
.detail-label { width: 60px; flex-shrink: 0; color: var(--text-muted); }
.detail-value { flex: 1; color: var(--text-primary); word-break: break-all; }
.detail-value.mono { font-family: var(--font-mono); font-size: 12px; }
.detail-section { margin: 16px 0 8px; font-size: 12px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.json-block { background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: 10px 12px; font-size: 12px; font-family: var(--font-mono); white-space: pre-wrap; word-break: break-all; color: var(--text-secondary); margin: 0; }
.json-block.error { color: #dc2626; }
</style>
