<template>
  <div v-loading="loading">
    <PageHeader title="工单中心" description="管理工单派发、现场处置、反馈、复核和关闭">
      <el-radio-group v-model="viewMode"><el-radio-button value="table"><el-icon><List /></el-icon></el-radio-button><el-radio-button value="board"><el-icon><Grid /></el-icon></el-radio-button><el-radio-button value="map"><el-icon><MapLocation /></el-icon></el-radio-button></el-radio-group>
      <el-button :icon="Refresh" :loading="loading" @click="load">刷新</el-button>
    </PageHeader>
    <section class="metric-strip"><div v-for="item in metrics" :key="item.label" class="metric-card"><strong>{{ item.value }}</strong><span>{{ item.label }}</span><small>{{ item.note }}</small></div></section>
    <el-tabs v-model="activeTab" class="secondary-tabs"><el-tab-pane label="全部工单" name="all" /><el-tab-pane :label="`我的待办 ${pendingCount}`" name="pending" /><el-tab-pane label="待派发" name="created" /><el-tab-pane label="处理中" name="processing" /><el-tab-pane label="待复核" name="review" /><el-tab-pane label="已闭环" name="closed" /></el-tabs>
    <div class="filter-bar"><el-input v-model="keyword" clearable placeholder="工单、告警、场景或责任人" :prefix-icon="Search" /><el-select v-model="severityFilter"><el-option label="全部等级" value="" /><el-option label="严重" value="critical" /><el-option label="高" value="high" /><el-option label="中" value="medium" /></el-select><span class="filter-spacer"></span><span>{{ filteredRows.length }} 张工单</span></div>

    <el-card v-if="viewMode === 'table'" class="workspace-card" shadow="never"><el-table :data="pagedRows" empty-text="暂无工单" @row-click="openDetail"><el-table-column prop="workorder_id" label="工单编号" min-width="170"><template #default="scope"><span class="entity-id">{{ scope.row.workorder_id }}</span><small class="cell-subtext">告警 {{ scope.row.alarm_id }}</small></template></el-table-column><el-table-column prop="scene" label="隐患场景" min-width="140" /><el-table-column label="等级" width="90"><template #default="scope"><el-tag :type="scope.row.severity === 'critical' ? 'danger' : 'warning'" effect="dark">{{ severityLabel(scope.row.severity) }}</el-tag></template></el-table-column><el-table-column prop="assignee" label="责任人" min-width="120" /><el-table-column label="位置" min-width="150"><template #default="scope">{{ locationText(scope.row.location) }}</template></el-table-column><el-table-column label="状态" width="105"><template #default="scope"><el-tag :type="statusTag(scope.row.status)" effect="plain">{{ statusLabel(scope.row.status) }}</el-tag></template></el-table-column><el-table-column label="更新时间" min-width="165"><template #default="scope">{{ formatDateTime(scope.row.updated_at) }}</template></el-table-column><el-table-column label="操作" width="235" fixed="right"><template #default="scope"><div class="list-actions" @click.stop><el-button link type="primary" @click="openDetail(scope.row)">详情</el-button><el-button link type="primary" :disabled="scope.row.status === 'closed'" @click="redispatch(scope.row)">改派</el-button><el-button v-if="reviewStatuses.includes(String(scope.row.status))" link type="success" @click="review(scope.row, 'approve')">复核通过</el-button><el-button v-if="reviewStatuses.includes(String(scope.row.status))" link type="danger" @click="review(scope.row, 'return')">退回</el-button></div></template></el-table-column></el-table><el-pagination v-model:current-page="page" v-model:page-size="pageSize" class="table-pagination" background layout="total, sizes, prev, pager, next" :page-sizes="[20, 50, 100]" :total="filteredRows.length" /></el-card>

    <section v-else-if="viewMode === 'board'" class="workorder-board"><div v-for="lane in lanes" :key="lane.key" class="board-lane"><header><strong>{{ lane.label }}</strong><span>{{ lane.rows.length }}</span></header><div class="board-list"><button v-for="row in lane.rows" :key="row.workorder_id" type="button" class="workorder-card" @click="openDetail(row)"><span class="entity-id">{{ row.workorder_id }}</span><strong>{{ row.scene }}</strong><small>{{ row.assignee || '待分配' }} · {{ locationText(row.location) }}</small><el-tag :type="row.severity === 'critical' ? 'danger' : 'warning'" size="small">{{ severityLabel(row.severity) }}</el-tag></button><el-empty v-if="lane.rows.length === 0" description="暂无" :image-size="46" /></div></div></section>

    <section v-else class="gis-page-layout workorder-map-layout"><RailwayGisMap :alarms="filteredRows" :selected-id="String(selected?.alarm_id || '')" :layers="{ routes: false, rules: true, alarms: true }" @select="openDetail" /><aside class="gis-detail-panel"><template v-if="selected"><h2>{{ selected.scene }}</h2><p class="entity-id">{{ selected.workorder_id }}</p><el-descriptions :column="1" border size="small"><el-descriptions-item label="状态">{{ statusLabel(selected.status) }}</el-descriptions-item><el-descriptions-item label="责任人">{{ selected.assignee || '待分配' }}</el-descriptions-item><el-descriptions-item label="位置">{{ locationText(selected.location) }}</el-descriptions-item></el-descriptions><div class="drawer-actions"><el-button type="primary" @click="openDetail(selected)">查看工单</el-button></div></template><el-empty v-else description="选择地图点位" /></aside></section>

    <el-drawer v-model="detailVisible" title="工单详情" size="660px"><template v-if="selected"><el-steps :active="workorderStep(selected.status)" finish-status="success" align-center><el-step title="工单创建" /><el-step title="接单到场" /><el-step title="现场处置" /><el-step title="复核关闭" /></el-steps><el-descriptions class="workorder-descriptions" :column="1" border><el-descriptions-item label="工单编号"><span class="entity-id">{{ selected.workorder_id }}</span></el-descriptions-item><el-descriptions-item label="关联告警"><el-button link type="primary" @click="router.push(`/alarms/${selected.alarm_id}`)">{{ selected.alarm_id }}</el-button></el-descriptions-item><el-descriptions-item label="隐患场景">{{ selected.scene }} / {{ selected.category }}</el-descriptions-item><el-descriptions-item label="责任人">{{ selected.assignee || '待分配' }}</el-descriptions-item><el-descriptions-item label="处置结果">{{ selected.close_result || '尚未提交' }}</el-descriptions-item><el-descriptions-item label="处置意见">{{ selected.comment || '-' }}</el-descriptions-item><el-descriptions-item label="状态">{{ statusLabel(selected.status) }}</el-descriptions-item></el-descriptions>
      <div class="drawer-actions workorder-action-bar"><el-button v-if="selected.status === 'created'" type="primary" @click="act(selected, 'ACCEPT')">接收工单</el-button><el-button v-if="selected.status === 'accepted'" type="primary" @click="act(selected, 'DEPART')">出发</el-button><el-button v-if="selected.status === 'en_route'" type="primary" @click="act(selected, 'ARRIVE')">到场签到</el-button><el-button v-if="selected.status === 'on_site'" type="primary" @click="act(selected, 'START_PROCESSING')">开始处置</el-button><el-button v-if="selected.status === 'processing'" type="success" @click="act(selected, 'SUBMIT')">提交处置</el-button><el-button v-if="selected.status === 'returned'" type="primary" @click="act(selected, 'REOPEN')">重新处置</el-button><el-button v-if="['submitted','reviewing'].includes(String(selected.status))" type="success" @click="act(selected, 'APPROVE')">复核通过</el-button><el-button v-if="['submitted','reviewing'].includes(String(selected.status))" type="danger" plain @click="act(selected, 'RETURN')">退回重办</el-button><el-button v-if="selected.status !== 'closed'" @click="redispatch(selected)">人工改派</el-button><el-button v-if="['submitted','reviewing'].includes(String(selected.status))" @click="requestReinspection(selected)">创建复飞任务</el-button><el-button @click="router.push({ path: '/gis', query: { workorderId: selected.workorder_id } })">地图定位</el-button></div>
      <div class="subsection-head evidence-head"><div><strong>现场证据</strong><span>整改前、中、后原始文件与摘要</span></div><div><el-select v-model="evidencePhase" size="small"><el-option label="整改前" value="BEFORE" /><el-option label="整改中" value="DURING" /><el-option label="整改后" value="AFTER" /></el-select><el-button type="primary" plain size="small" :icon="Upload" @click="evidenceInput?.click()">上传证据</el-button><input ref="evidenceInput" class="hidden-file-input" type="file" accept="image/*,video/*,audio/*,.pdf" @change="uploadEvidence" /></div></div>
      <div v-if="evidence.length" class="evidence-file-grid"><a v-for="item in evidence" :key="item.attachment_id" :href="workorderEvidenceUrl(String(item.attachment_id))" target="_blank"><el-icon><Picture /></el-icon><span><strong>{{ item.file_name }}</strong><small>{{ evidencePhaseLabel(item.phase) }} · {{ fileSize(item.size_bytes) }}</small></span></a></div><el-empty v-else description="尚未上传现场证据" :image-size="54" />
      <h3 class="drawer-section-title">处置时间轴</h3><el-timeline><el-timeline-item v-for="item in actions" :key="item.action_id" :timestamp="formatDateTime(item.created_at)" placement="top"><strong>{{ actionLabel(item.action_type) }}</strong><p>{{ item.operator_name }} · {{ item.comment || item.result || '状态已更新' }}</p></el-timeline-item></el-timeline>
    </template></el-drawer>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { Grid, List, MapLocation, Picture, Refresh, Search, Upload } from "@element-plus/icons-vue";
import PageHeader from "../../components/common/PageHeader.vue"; import RailwayGisMap from "../../components/gis/RailwayGisMap.vue";
import { createReinspection, executeWorkorderAction, redispatchWorkorder, uploadWorkorderEvidence, workorderActions, workorderEvidence, workorderEvidenceUrl, workorders } from "../../services/api";
import { safeObject, severityLabel, statusLabel, statusTag, type Row } from "../../types/demo-run";

const route = useRoute(); const router = useRouter(); const loading = ref(false); const rows = ref<Row[]>([]); const activeTab = ref(String(route.query.tab || "all")); const keyword = ref(""); const severityFilter = ref(""); const viewMode = ref<"table" | "board" | "map">("table"); const selected = ref<Row | null>(null); const detailVisible = ref(false); const page = ref(1); const pageSize = ref(50); const actions = ref<Row[]>([]); const evidence = ref<Row[]>([]); const evidencePhase = ref("AFTER"); const evidenceInput = ref<HTMLInputElement | null>(null);
const filteredRows = computed(() => rows.value.filter((row) => matchTab(row) && (!severityFilter.value || row.severity === severityFilter.value) && (!keyword.value || `${row.workorder_id} ${row.alarm_id} ${row.scene} ${row.assignee}`.toLowerCase().includes(keyword.value.toLowerCase()))));
const pagedRows = computed(() => filteredRows.value.slice((page.value - 1) * pageSize.value, page.value * pageSize.value));
const pendingCount = computed(() => rows.value.filter((row) => row.status !== "closed").length);
const metrics = computed(() => [{ label: "工单总数", value: rows.value.length, note: "全部处置事项" }, { label: "待派发", value: count("created"), note: "需要责任匹配" }, { label: "处理中", value: rows.value.filter((row) => processingStatuses.includes(String(row.status))).length, note: "现场正在处置" }, { label: "待复核", value: rows.value.filter((row) => reviewStatuses.includes(String(row.status))).length, note: "等待复核结论" }, { label: "已闭环", value: count("closed"), note: "处置完成" }]);
const processingStatuses = ["accepted", "en_route", "on_site", "processing", "returned", "reinspection_required"]; const reviewStatuses = ["review", "submitted", "reviewing"];
const lanes = computed(() => [{ key: "created", label: "待派发", rows: rows.value.filter((row) => row.status === "created") }, { key: "processing", label: "处理中", rows: rows.value.filter((row) => processingStatuses.includes(String(row.status))) }, { key: "review", label: "待复核", rows: rows.value.filter((row) => reviewStatuses.includes(String(row.status))) }, { key: "closed", label: "已闭环", rows: rows.value.filter((row) => row.status === "closed") }]);
function count(status: string) { return rows.value.filter((row) => row.status === status).length; }
function matchTab(row: Row) { if (activeTab.value === "all") return true; if (activeTab.value === "pending") return row.status !== "closed"; if (activeTab.value === "processing") return processingStatuses.includes(String(row.status)); if (activeTab.value === "review") return reviewStatuses.includes(String(row.status)); return row.status === activeTab.value; }
function locationText(value: unknown) { const location = safeObject(value); return [location.mileage, location.distance_to_track_m ? `${location.distance_to_track_m}m` : ""].filter(Boolean).join(" / ") || "线路邻近"; }
function formatDateTime(value: unknown) { return value ? new Date(String(value)).toLocaleString("zh-CN", { hour12: false }) : "-"; }
function workorderStep(status: unknown) { return ({ created: 1, accepted: 2, en_route: 2, on_site: 2, processing: 3, returned: 3, submitted: 3, reviewing: 3, reinspection_required: 3, closed: 4 } as Record<string, number>)[String(status)] || 1; }
async function load() { loading.value = true; try { rows.value = await workorders(); const id = String(route.params.workorderId || ""); if (id) { const row = rows.value.find((item) => String(item.workorder_id) === id); if (row) openDetail(row); } } finally { loading.value = false; } }
async function openDetail(row: Row) { selected.value = row; detailVisible.value = true; router.replace({ path: `/workorders/${row.workorder_id}`, query: route.query }); await loadDetail(row); }
async function loadDetail(row: Row) { [actions.value, evidence.value] = await Promise.all([workorderActions(String(row.workorder_id)), workorderEvidence(String(row.workorder_id))]); }
async function redispatch(row: Row) { try { const result = await ElMessageBox.prompt("请输入新的责任人或班组", "人工改派", { inputValue: String(row.assignee || "专业复核人员"), inputValidator: (value) => Boolean(value) || "责任人不能为空" }); await redispatchWorkorder(String(row.workorder_id), result.value); ElMessage.success("工单已重新派发"); detailVisible.value = false; await load(); } catch { /* cancelled */ } }
async function review(row: Row, action: "approve" | "return") { await act(row, action === "approve" ? "APPROVE" : "RETURN"); }
async function act(row: Row, action: string) { await executeWorkorderAction(String(row.workorder_id), action, action === "APPROVE" ? "复核通过" : "", action === "RETURN" ? "证据或处置结果需要补充" : ""); ElMessage.success("工单状态已更新"); await load(); const current = rows.value.find((item) => item.workorder_id === row.workorder_id); if (current) { selected.value = current; await loadDetail(current); } }
async function uploadEvidence(event: Event) { const input = event.target as HTMLInputElement; const file = input.files?.[0]; if (!file || !selected.value) return; await uploadWorkorderEvidence(String(selected.value.workorder_id), evidencePhase.value, file); ElMessage.success("现场证据已上传并记录摘要"); input.value = ""; await loadDetail(selected.value); }
async function requestReinspection(row: Row) { const result = await createReinspection(String(row.workorder_id)); ElMessage.success(`复飞任务已创建：${result.reinspection_task_id}`); await load(); const current = rows.value.find((item) => item.workorder_id === row.workorder_id); if (current) { selected.value = current; await loadDetail(current); } }
function evidencePhaseLabel(value: unknown) { return ({ BEFORE: "整改前", DURING: "整改中", AFTER: "整改后", REVIEW: "复核" } as Record<string, string>)[String(value)] || String(value); }
function actionLabel(value: unknown) { return ({ ACCEPT: "接收工单", DEPART: "出发", ARRIVE: "到场签到", START_PROCESSING: "开始处置", SUBMIT: "提交处置", APPROVE: "复核通过", RETURN: "退回重办", EVIDENCE_UPLOADED: "上传现场证据" } as Record<string, string>)[String(value)] || String(value); }
function fileSize(value: unknown) { const bytes = Number(value || 0); return bytes >= 1024 * 1024 ? `${(bytes / 1024 / 1024).toFixed(1)} MB` : `${Math.max(1, Math.round(bytes / 1024))} KB`; }
watch(detailVisible, (visible) => { if (!visible && route.params.workorderId) router.replace({ path: "/workorders", query: route.query }); });
watch([activeTab, keyword, severityFilter, pageSize], () => { page.value = 1; });
onMounted(load);
</script>
