﻿<template>
  <section class="manage-page">
    <p class="breadcrumb">
      数据管理 / <span>企业端 · 资产月度上报</span> / <span>{{ monthlySub === 'current' ? '本月上报清单' : '历史上报记录' }}</span>
    </p>
    <div class="page-header">
      <h2 class="page-title">月度资产上报</h2>
    </div>

    <div class="sub-tabs">
      <BaseButton
        text="本月上报清单"
        :class="{ 'nav-tab-item--active': monthlySub === 'current' }"
        @click="switchArchiveSub('current')"
      />
      <BaseButton
        text="历史上报记录"
        :class="{ 'nav-tab-item--active': monthlySub === 'history' }"
        @click="switchArchiveSub('history')"
      />
    </div>

    <template v-if="monthlySub === 'current'">
      <div class="period-panel">
        <div class="status-strip">
          <span>本账期 <strong>{{ currentPeriod }}</strong> · 截止 <strong>{{ periodDeadline }}</strong></span>
          <span class="status-tag" :class="`status-tag--${statusTagType}`">{{ statusTagLabel }}</span>
        </div>

        <div class="flow-stepper">
          <template v-for="(step, idx) in flowSteps" :key="step.key">
            <div
              v-if="idx > 0"
              class="flow-stepper__line"
              :class="{ 'flow-stepper__line--done': visualStepIndex >= idx }"
            />
            <div class="flow-stepper__node">
              <div class="flow-stepper__dot" :class="getDotClass(idx)" />
              <span class="flow-stepper__label">{{ step.label }}</span>
            </div>
          </template>
        </div>

        <p v-if="reportingPhase === 'pending'" class="period-notice">
          本账期已提交/审核中，清单只读。通过或驳回后可重新编辑。
        </p>
        <p v-else-if="reportingPhase === 'passed'" class="period-notice">
          本账期已通过审核，可继续编辑并重新提交。
        </p>
        <p v-else-if="reportingPhase === 'rejected'" class="period-notice period-notice--warn">
          本账期已被驳回，请修改清单后重新提交。
        </p>
      </div>

      <div class="panel">
        <div class="panel-toolbar">
          <div class="panel-toolbar__left">
            <SectionHeader title="本月待上报资产清单" />

          </div>
          <div class="action-row">
            <BaseButton
              text="新增上报资产"
              variant="warning"
              :class="{ 'nav-tab-item--disabled': isReportLocked }"
              @click="!isReportLocked && (showPickModal = true)"
            />
            <BaseButton
              text="批量删除"
              variant="outline"
              :class="{ 'nav-tab-item--disabled': isReportLocked }"
              @click="handleBatchDelete"
            />
            <BaseButton
              text="清空清单"
              variant="outline"
              :class="{ 'nav-tab-item--disabled': isReportLocked }"
              @click="handleClearList"
            />
            <BaseButton
              text="数据一键校验"
              variant="outline"
              :class="{ 'nav-tab-item--disabled': isReportLocked }"
              @click="handleValidateAll"
            />
            <BaseButton
              text="提交上报"
              variant="primary"
              :class="{ 'nav-tab-item--disabled': isReportLocked || submitting }"
              @click="handleSubmitReport"
            />
          </div>
        </div>
        <div class="data-table">
          <div class="data-table__header">
            <span style="width: 40px">
              <input
                v-if="!isReportLocked"
                type="checkbox"
                :checked="allSelected"
                @change="toggleSelectAll"
              />
            </span>
            <span v-for="col in queueColumns" :key="col.key" :style="{ width: col.width }">{{ col.label }}</span>
          </div>
          <div v-if="queueRows.length === 0" class="data-table__empty">
            {{
              reportingPhase === 'passed'
                ? '本账期已通过审核'
                : isReportLocked
                  ? '清单暂无数据'
                  : '暂无资产，请点击「新增上报资产」'
            }}
          </div>
          <div v-for="item in queueRows" :key="item.id" class="data-table__row">
            <span style="width: 40px">
              <input
                v-if="!isReportLocked"
                v-model="selectedIds"
                type="checkbox"
                :value="item.id"
              />
            </span>
            <span :style="{ width: queueColumns[0].width }">{{ item.code }}</span>
            <span :style="{ width: queueColumns[1].width }">{{ item.group }}</span>
            <span :style="{ width: queueColumns[2].width }">{{ item.name }}</span>
            <span :style="{ width: queueColumns[3].width }">{{ item.buildArea }}</span>
            <span :style="{ width: queueColumns[4].width }">{{ item.rentArea }}</span>
            <span :style="{ width: queueColumns[5].width }">{{ item.idleArea }}</span>
            <span :style="{ width: queueColumns[6].width }">{{ item.selfArea }}</span>
            <span :style="{ width: queueColumns[7].width }">{{ item.lendArea }}</span>
            <span :style="{ width: queueColumns[8].width }">{{ item.utilState }}</span>
            <span :style="{ width: queueColumns[9].width }">
              <template v-if="isReportLocked">
                <span class="muted">只读</span>
              </template>
              <template v-else>
                <button type="button" class="link-btn" @click="handleEditItem(item.id)">编辑</button>
                <button type="button" class="link-btn" @click="handleRemoveItem(item.id)">移除</button>
              </template>
            </span>
          </div>
        </div>
        <p class="panel-hint">清单内 <strong>{{ queueRows.length }}</strong> 条 · 已填报 <strong>{{ filledCount }}</strong> 条</p>
      </div>
    </template>

    <template v-else>
      <div class="panel">
        <div class="filter-bar">
          <BaseSelect text="上报年月" :selectedText="histPeriod" :options="periodOptions" @selected="histPeriod = $event" />
          <BaseSelect text="上报状态" :selectedText="histStatus" :options="statusOptions" @selected="histStatus = $event" />
          <label class="filter-item">
            <span>填报人</span>
            <input v-model="histReporter" type="text" placeholder="姓名" />
          </label>
          <BaseButton text="重置" variant="outline" @click="resetHistoryFilters" />
          <BaseButton text="导出往期上报报表" variant="outline" @click="handleHistExport" />
        </div>
      </div>
      <div class="panel">
        <div class="data-table">
          <div class="data-table__header">
            <span v-for="col in historyColumns" :key="col.key" :style="{ width: col.width }">{{ col.label }}</span>
          </div>
          <div v-if="historyLoading" class="data-table__empty">加载中…</div>
          <div v-else-if="filteredHistoryRows.length === 0" class="data-table__empty">暂无历史上报记录</div>
          <template v-else>
            <div v-for="row in filteredHistoryRows" :key="row.id" class="data-table__row">
              <span :style="{ width: historyColumns[0].width }">{{ row.period }}</span>
              <span :style="{ width: historyColumns[1].width }">{{ row.group }}</span>
              <span :style="{ width: historyColumns[2].width }">{{ row.billNo }}</span>
              <span :style="{ width: historyColumns[3].width }">{{ row.submittedAt }}</span>
              <span :style="{ width: historyColumns[4].width }">{{ row.reporter }}</span>
              <span :style="{ width: historyColumns[5].width }">
                <span class="status-tag" :class="`status-tag--${row.statusType}`">{{ row.status }}</span>
              </span>
              <span :style="{ width: historyColumns[6].width }">
                <button type="button" class="link-btn" @click="handleHistDetail(row)">查看详情</button>
                <button type="button" class="link-btn" @click="handleHistAudit(row)">审批记录</button>
              </span>
            </div>
          </template>
        </div>
      </div>
    </template>

    <PickAssetModal
      v-model:visible="showPickModal"
      :exclude-ids="queueIds"
      @confirm="handlePickConfirm"
    />
    <MonthlyEditModal
      v-model:visible="showEditModal"
      :asset="editingAsset"
      @save="handleEditSave"
    />
    <HistDetailModal v-model:visible="showHistDetail" :record="histDetailRecord" />
    <HistAuditTrailModal v-model:visible="showHistAudit" :record="histAuditRecord" />
  </section>
</template>

<script setup>
import { showAlert, showConfirm, showError, showSuccess, showWarning } from '@/utils/message';
import { exportTableExcel } from '@/utils/exportExcel';
import { computed, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import SectionHeader from '@/components/base/SectionHeader.vue';
import BaseSelect from '@/components/base/BaseSelect.vue';
import BaseButton from '@/components/base/BaseButton.vue';
import PickAssetModal from '@/components/manage/asset/PickAssetModal.vue';
import MonthlyEditModal from '@/components/manage/report/MonthlyEditModal.vue';
import HistDetailModal from '@/components/manage/audit/HistDetailModal.vue';
import HistAuditTrailModal from '@/components/manage/audit/HistAuditTrailModal.vue';
import { useEnterpriseStore, REPORT_STATE } from '@/store/enterprise';
import { useNotificationStore } from '@/store/notification';
import { useUserStore } from '@/store/user';
import { parseManageRoute, buildManageRoute } from '@/utils/manageRoutes';
import { resolveManageEnterprise, assetBelongsToManageScope } from '@/utils/manageContext';
import { useFilterStore } from '@/store/filter';
import { resolveUtilState } from '@/utils/resolveUtilState';
import {
  buildBillNo,
  extractFillMonth,
  buildAuditTrail,
  normalizeGroupName,
  formatDateTime,
  getFillTime,
  getAuditTime,
  getReporter,
  extractPeriod,
  sumBuildAreaWan,
} from '@/utils/aggregateReportRecords';
import { updateAudit, submitAssetEdit, updateContent } from '@/api/enterpriseList';
import { buildContentPayload, resolveAssetRecord } from '@/utils/assetDetailFields';
import { COLUMN_ID, MODEL_ID } from '@/config';
const enterpriseStore = useEnterpriseStore();
const notificationStore = useNotificationStore();
const userStore = useUserStore();
const filterStore = useFilterStore();
const route = useRoute();
const router = useRouter();

const currentEnterprise = computed(() => resolveManageEnterprise(userStore.userInfo));

const currentManageGroup = computed(() => normalizeGroupName(filterStore.selectManageGroup));

const monthlySub = ref('current');

const pad2 = (n) => String(n).padStart(2, '0');

/** 本账期：当前自然月 */
const currentPeriod = computed(() => {
  const now = new Date();
  return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}`;
});

/** 截止：次月 1 日 */
const periodDeadline = computed(() => {
  const now = new Date();
  const month = now.getMonth() + 1;
  const nextMonth = month === 12 ? 1 : month + 1;
  const nextYear = month === 12 ? now.getFullYear() + 1 : now.getFullYear();
  return `${nextYear}-${pad2(nextMonth)}-01`;
});

const showPickModal = ref(false);
const showEditModal = ref(false);
const editingAssetId = ref(null);
const selectedIds = ref([]);
const monthlyQueue = ref([]);
/** 按资产 id 暂存编辑草稿，不反映到清单表格 */
const monthlyDrafts = ref({});
/** 已点击「提交上报」，整页进入审核等待态 */
const reportLocked = ref(false);
const submitting = ref(false);
const savingEdit = ref(false);
const showHistDetail = ref(false);
const histDetailRecord = ref(null);
const showHistAudit = ref(false);
const histAuditRecord = ref(null);

const flowSteps = [
  { key: 'unsubmitted', label: '未提交' },
  { key: 'draft', label: '草稿已填写' },
  { key: 'submitted', label: '已提交' },
  { key: 'pending', label: '审核中' },
  { key: 'passed', label: '已通过/已驳回' },
];

const readPersistedQueueIds = () => {
  try {
    const raw = localStorage.getItem(queueStorageKey.value);
    if (!raw) return new Set();
    const saved = JSON.parse(raw);
    return new Set((saved.itemIds || []).map(String));
  } catch {
    return new Set();
  }
};

const readPersistedQueueMeta = () => {
  try {
    const raw = localStorage.getItem(queueStorageKey.value);
    if (!raw) return null;
    return JSON.parse(raw);
  } catch {
    return null;
  }
};

const extractReportMonth = (item) => {
  const fillMonth = extractFillMonth(item);
  if (fillMonth) return fillMonth;
  const time = item?.update_time ?? item?.audit_time;
  if (time == null || time === '') return '';
  const text = String(time);
  if (/^\d{4}-\d{2}/.test(text)) return text.slice(0, 7);
  const d = new Date(time);
  if (Number.isNaN(d.getTime())) return '';
  const pad = (n) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;
};

/** 本账期清单/审核状态：仅按青浦集团（c_ssqpjt）归属，与历史上报一致 */
const belongsToMonthlyQueue = (item) => {
  if (!item?.id) return false;
  return normalizeGroupName(item.c_ssqpjt) === currentManageGroup.value;
};

const matchesReportScope = (item) => {
  if (!belongsToMonthlyQueue(item)) return false;
  const period = currentPeriod.value;
  if (readPersistedQueueIds().has(String(item.id))) return true;
  return extractReportMonth(item) === period;
};

const filterByCurrentScope = (list) => list.filter(matchesReportScope);

const pendingPeriodItems = computed(() => filterByCurrentScope(enterpriseStore.pendingList));

const rejectedPeriodItems = computed(() => filterByCurrentScope(enterpriseStore.rejectedList));

const approvedPeriodItems = computed(() => filterByCurrentScope(enterpriseStore.approvedList));

const queueStorageKey = computed(
  () => `monthly-queue:${currentPeriod.value}:${currentManageGroup.value}`
);

const sanitizeMonthlyQueue = () => {
  monthlyQueue.value = monthlyQueue.value.filter(belongsToMonthlyQueue);
};

const persistQueue = () => {
  try {
    if (!monthlyQueue.value.length) {
      clearQueueStorage();
      return;
    }
    localStorage.setItem(
      queueStorageKey.value,
      JSON.stringify({
        reportLocked: reportLocked.value,
        itemIds: monthlyQueue.value.map((item) => item.id),
        filledIds: monthlyQueue.value.filter((item) => item._monthlyFilled).map((item) => item.id),
        drafts: monthlyDrafts.value,
      })
    );
  } catch (e) {
    console.log('清单持久化失败：', e);
  }
};

const getPersistedQueueState = () => {
  try {
    const raw = localStorage.getItem(queueStorageKey.value);
    if (!raw) return 'missing';
    const saved = JSON.parse(raw);
    if (!Array.isArray(saved?.itemIds) || !saved.itemIds.length) return 'empty';
    return 'hasItems';
  } catch {
    return 'missing';
  }
};

const buildQueueSources = () => {
  const byId = new Map();
  [
    ...enterpriseStore.pendingList,
    ...enterpriseStore.rejectedList,
    ...enterpriseStore.approvedList,
    ...enterpriseStore.submittedList,
  ].forEach((item) => byId.set(String(item.id), item));
  return byId;
};

const mapQueueFromItems = (items, filledSet = null) =>
  items.map((item) => ({
    ...item,
    _monthlyFilled: filledSet ? filledSet.has(String(item.id)) : true,
  }));

const restoreQueueFromStorage = () => {
  try {
    const saved = readPersistedQueueMeta();
    if (!saved) return 'missing';
    if (!Array.isArray(saved?.itemIds) || !saved.itemIds.length) {
      monthlyQueue.value = [];
      monthlyDrafts.value = saved?.drafts || {};
      reportLocked.value = Boolean(saved?.reportLocked);
      return 'empty';
    }

    const filledSet = new Set((saved.filledIds || []).map(String));
    const byId = buildQueueSources();

    monthlyQueue.value = saved.itemIds
      .map((id) => byId.get(String(id)))
      .filter(Boolean)
      .filter(belongsToMonthlyQueue)
      .map((item) => ({
        ...item,
        _monthlyFilled: filledSet.has(String(item.id)),
      }));

    monthlyDrafts.value = saved.drafts || {};
    reportLocked.value = Boolean(saved.reportLocked);
    return monthlyQueue.value.length > 0 ? 'restored' : 'empty';
  } catch (e) {
    console.log('清单恢复失败：', e);
    return 'missing';
  }
};

const hydrateQueueFromAuditStates = () => {
  const byId = buildQueueSources();
  const savedIds = [...readPersistedQueueIds()];
  const saved = readPersistedQueueMeta();

  if (savedIds.length) {
    const restored = savedIds
      .map((id) => byId.get(String(id)))
      .filter(Boolean)
      .filter(belongsToMonthlyQueue);
    if (restored.length) {
      const filledSet = new Set((saved?.filledIds || []).map(String));
      monthlyQueue.value = mapQueueFromItems(restored, filledSet);
      monthlyDrafts.value = saved?.drafts || monthlyDrafts.value;
      return true;
    }
  }

  const auditItems = [
    ...pendingPeriodItems.value,
    ...rejectedPeriodItems.value,
  ];
  const unique = [...new Map(auditItems.map((item) => [String(item.id), item])).values()];
  if (!unique.length) return false;

  monthlyQueue.value = mapQueueFromItems(unique);
  return true;
};

const syncMonthlyQueue = () => {
  if (monthlyQueue.value.length) {
    mergeQueueFromBackend();
    sanitizeMonthlyQueue();
    return;
  }

  const queueState = restoreQueueFromStorage();
  if (queueState === 'restored') {
    mergeQueueFromBackend();
    sanitizeMonthlyQueue();
    return;
  }

  if (hydrateQueueFromAuditStates()) {
    mergeQueueFromBackend();
    sanitizeMonthlyQueue();
    return;
  }

  if (getPersistedQueueState() === 'missing') {
    bootstrapQueueFromBackend();
    sanitizeMonthlyQueue();
  }
};

const mergeQueueFromBackend = () => {
  if (!monthlyQueue.value.length) return;
  const byId = buildQueueSources();
  monthlyQueue.value = monthlyQueue.value
    .map((item) => {
      const fresh = byId.get(String(item.id));
      if (!fresh) return item;
      return {
        ...fresh,
        _monthlyFilled: item._monthlyFilled,
      };
    })
    .filter(belongsToMonthlyQueue);
};

const bootstrapQueueFromBackend = () => {
  if (getPersistedQueueState() !== 'missing') return false;

  const byId = new Map();
  [...pendingPeriodItems.value, ...rejectedPeriodItems.value].forEach((item) =>
    byId.set(String(item.id), item)
  );

  if (!byId.size) return false;

  monthlyQueue.value = [...byId.values()].map((item) => ({
    ...item,
    _monthlyFilled: true,
  }));
  return true;
};

const queueAnyPending = computed(() =>
  monthlyQueue.value.some((item) =>
    pendingPeriodItems.value.some((p) => String(p.id) === String(item.id))
  )
);

const queueAnyRejected = computed(() =>
  monthlyQueue.value.some((item) =>
    rejectedPeriodItems.value.some((r) => String(r.id) === String(item.id))
  )
);

const queueAllApproved = computed(
  () =>
    monthlyQueue.value.length > 0 &&
    monthlyQueue.value.every((item) =>
      approvedPeriodItems.value.some((a) => String(a.id) === String(item.id))
    )
);

/** 本账期存在审核中资产时锁定清单（含本地清单为空但后端有待审数据） */
const isReportLocked = computed(() => {
  if (pendingPeriodItems.value.length === 0) return false;
  if (monthlyQueue.value.length > 0) return queueAnyPending.value;
  return readPersistedQueueIds().size > 0 || pendingPeriodItems.value.length > 0;
});

const reportingPhase = computed(() => {
  const hasQueue = monthlyQueue.value.length > 0;
  const hasPending = pendingPeriodItems.value.length > 0;
  const hasRejected = rejectedPeriodItems.value.length > 0;
  const hasApproved = approvedPeriodItems.value.length > 0;

  if ((hasQueue && queueAnyPending.value) || (!hasQueue && hasPending)) return 'pending';
  if ((hasQueue && queueAnyRejected.value) || (!hasQueue && hasRejected && !hasPending)) {
    return 'rejected';
  }
  if ((hasQueue && queueAllApproved.value) || (!hasQueue && hasApproved && !hasPending && !hasRejected)) {
    return 'passed';
  }
  if (!hasQueue) return 'unsubmitted';
  const allFilled = monthlyQueue.value.every(
    (item) => item._monthlyFilled || monthlyDrafts.value[String(item.id)]
  );
  return allFilled ? 'draft' : 'unsubmitted';
});

const syncQueueAuditState = () => {
  reportLocked.value = isReportLocked.value;
};

const visualStepIndex = computed(() => {
  const map = {
    unsubmitted: 0,
    draft: 1,
    submitted: 2,
    pending: 3,
    rejected: 4,
    passed: 4,
  };
  return map[reportingPhase.value] ?? 0;
});

const getDotClass = (idx) => {
  const current = visualStepIndex.value;
  const phase = reportingPhase.value;
  if (idx < current) return 'flow-stepper__dot--done';
  if (idx === current) {
    if (phase === 'rejected') return 'flow-stepper__dot--rejected';
    if (phase === 'passed') return 'flow-stepper__dot--passed';
    return 'flow-stepper__dot--active';
  }
  return 'flow-stepper__dot--future';
};

const statusTagLabel = computed(() => {
  const labels = {
    unsubmitted: '填报中',
    draft: '草稿已填写',
    submitted: '已提交',
    pending: '审核中',
    rejected: '已驳回',
    passed: '已通过',
  };
  return labels[reportingPhase.value] || '填报中';
});

const statusTagType = computed(() => {
  const types = {
    unsubmitted: 'orange',
    draft: 'orange',
    submitted: 'orange',
    pending: 'orange',
    rejected: 'red',
    passed: 'green',
  };
  return types[reportingPhase.value] || 'orange';
});

const histPeriod = ref('全部');
const histStatus = ref('全部');
const histReporter = ref('');

const historyLoading = computed(
  () =>
    enterpriseStore.pendingLoading ||
    enterpriseStore.approvedLoading ||
    enterpriseStore.rejectedLoading
);

const queueColumns = [
  { key: 'code', label: '资产编号', width: '140px' },
  { key: 'group', label: '所属集团', width: '120px' },
  { key: 'name', label: '资产名称', width: '180px' },
  { key: 'buildArea', label: '实际建筑面积（㎡）', width: '160px' },
  { key: 'rentArea', label: '出租', width: '80px' },
  { key: 'idleArea', label: '闲置', width: '80px' },
  { key: 'selfArea', label: '自用', width: '80px' },
  { key: 'lendArea', label: '出借', width: '80px' },
  { key: 'utilState', label: '利用状态', width: '100px' },
  { key: 'action', label: '操作', width: '120px' },
];

const mapQueueItem = (item) => ({
  id: item.id,
  code: item.c_bh || '暂无',
  group: item.c_ssjt || item.c_ssqpjt || '暂无',
  name: item.c_qymc || '暂无',
  buildArea: Number(item.c_sjjzmj || 0).toLocaleString('zh-CN'),
  rentArea: Number(item.c_czmj || 0).toLocaleString('zh-CN'),
  idleArea: Number(item.c_xzmj || 0).toLocaleString('zh-CN'),
  selfArea: Number(item.c_zymj || 0).toLocaleString('zh-CN'),
  lendArea: Number(item.c_cjmj || 0).toLocaleString('zh-CN'),
  utilState: resolveUtilState(item),
  filled: Boolean(item._monthlyFilled || monthlyDrafts.value[String(item.id)]),
});

const displayQueue = computed(() => monthlyQueue.value.map(applyDraft));

const queueRows = computed(() => displayQueue.value.map(mapQueueItem));

const queueIds = computed(() => monthlyQueue.value.map((item) => String(item.id)));

const filledCount = computed(() => queueRows.value.filter((item) => item.filled).length);

const allSelected = computed(
  () =>
    !isReportLocked.value &&
    queueRows.value.length > 0 &&
    queueRows.value.every((item) => selectedIds.value.includes(item.id))
);

const toggleSelectAll = (event) => {
  if (event.target.checked) {
    selectedIds.value = queueRows.value.map((item) => item.id);
  } else {
    selectedIds.value = [];
  }
};

const applyDraft = (item) => {
  const draft = monthlyDrafts.value[String(item.id)];
  return draft ? { ...item, ...draft } : { ...item };
};

const editingAsset = computed(() => {
  if (editingAssetId.value == null) return null;
  const item = monthlyQueue.value.find((row) => row.id === editingAssetId.value);
  return item ? applyDraft(item) : null;
});

const clearDrafts = (ids) => {
  const next = { ...monthlyDrafts.value };
  ids.forEach((id) => {
    delete next[String(id)];
  });
  monthlyDrafts.value = next;
};

const handlePickConfirm = (pickedItems) => {
  if (isReportLocked.value) return;
  let added = 0;
  pickedItems.forEach((item) => {
    const id = String(item.id);
    if (!id || !belongsToMonthlyQueue(item)) return;
    if (!assetBelongsToManageScope(item)) return;
    if (monthlyQueue.value.some((r) => String(r.id) === id)) return;
    monthlyQueue.value.push(item);
    added++;
  });
  if (added > 0) {
    persistQueue();
    showSuccess(`已加入 ${added} 条（已去重）`);
  }
};

const handleBatchDelete = async () => {
  if (isReportLocked.value) return;
  if (!selectedIds.value.length) {
    showWarning('请先勾选要删除的资产');
    return;
  }
  const count = selectedIds.value.length;
  if (!(await showConfirm(`确认删除选中的 ${count} 条资产？`))) return;

  const toDelete = new Set(selectedIds.value.map((id) => String(id)));
  monthlyQueue.value = monthlyQueue.value.filter((item) => !toDelete.has(String(item.id)));
  clearDrafts([...toDelete]);
  selectedIds.value = [];
  persistQueue();
};

const handleClearList = async () => {
  if (isReportLocked.value) return;
  if (!monthlyQueue.value.length) {
    showWarning('清单为空');
    return;
  }
  if (!(await showConfirm('确认清空本月待上报清单？'))) return;

  monthlyQueue.value = [];
  monthlyDrafts.value = {};
  selectedIds.value = [];
  persistQueue();
};

const handleRemoveItem = async (id) => {
  if (isReportLocked.value) return;
  const row = queueRows.value.find((item) => item.id === id);
  const label = row?.code || '该资产';
  if (!(await showConfirm(`确认从清单中移除 ${label}？`))) return;

  monthlyQueue.value = monthlyQueue.value.filter((item) => item.id !== id);
  clearDrafts([id]);
  selectedIds.value = selectedIds.value.filter((selectedId) => selectedId !== id);
  persistQueue();
};

const handleEditItem = (id) => {
  if (isReportLocked.value) return;
  editingAssetId.value = id;
  showEditModal.value = true;
};

const buildMonthlyPatch = (item) => ({
  c_czmj: item.c_czmj,
  c_xzmj: item.c_xzmj,
  c_zymj: item.c_zymj,
  c_cjmj: item.c_cjmj,
  c_fwyt_yt1: item.c_fwyt_yt1,
});

const handleEditSave = async ({ item, isDraft }) => {
  const id = String(item.id);
  const index = monthlyQueue.value.findIndex((row) => String(row.id) === id);
  if (index < 0) return;

  if (isDraft) {
    monthlyDrafts.value = {
      ...monthlyDrafts.value,
      [id]: buildMonthlyPatch(item),
    };
    persistQueue();
    return;
  }

  const original = monthlyQueue.value[index];
  const patch = buildMonthlyPatch(item);

  savingEdit.value = true;
  try {
    await updateContent({
      content: buildContentPayload(original, patch),
      columnId: COLUMN_ID,
      modelId: MODEL_ID,
    });

    monthlyQueue.value[index] = {
      ...resolveAssetRecord({ ...original, ...patch }),
      _monthlyFilled: true,
    };
    clearDrafts([id]);
    persistQueue();
    showSuccess('保存成功');
  } catch (e) {
    console.log('月度填报保存异常：', e);
    showError(e?.message || e?.msg || '保存失败，请稍后重试');
  } finally {
    savingEdit.value = false;
  }
};

const monthlyAreaSum = (item) =>
  Number(item.c_czmj || 0) +
  Number(item.c_xzmj || 0) +
  Number(item.c_zymj || 0) +
  Number(item.c_cjmj || 0);

const validateMonthlyItem = (item) => {
  if (!item._monthlyFilled) return '未填报';

  const buildArea = Number(item.c_sjjzmj || 0);
  const sum = monthlyAreaSum(item);
  if (Math.abs(sum - buildArea) > 0.01) {
    return `四类使用面积之和须等于实际建筑面积（当前合计 ${sum.toFixed(2)}㎡，应为 ${buildArea.toFixed(2)}㎡）`;
  }
  return '';
};

const formatQueueItemLabel = (item, index) => {
  const parts = [
    `${index + 1}.`,
    item.c_bh ? `编号 ${item.c_bh}` : null,
    item.c_qymc || null,
    item.c_ssqpjt || item.c_ssjt || null,
  ].filter(Boolean);
  return parts.join(' · ');
};

const collectQueueErrors = () => {
  if (!monthlyQueue.value.length) {
    return ['清单为空'];
  }
  const errs = [];
  monthlyQueue.value.forEach((item, index) => {
    const err = validateMonthlyItem(item);
    if (err) errs.push(`${formatQueueItemLabel(item, index)}：${err}`);
  });
  return errs;
};

const showValidationErrors = (errs) => {
  const preview = errs.slice(0, 5).join('\n');
  const more = errs.length > 5 ? `\n… 还有 ${errs.length - 5} 条未通过` : '';
  showAlert(`校验未通过（共 ${errs.length} 条）\n${preview}${more}`, 'warning', { duration: 6000 });
};

const validateQueue = () => {
  const errs = collectQueueErrors();
  if (errs.length) {
    showValidationErrors(errs);
    return false;
  }
  return true;
};

const handleValidateAll = () => {
  if (isReportLocked.value) return;
  if (validateQueue()) {
    showSuccess('全部校验通过');
  }
};

const getQueueItemAuditState = (item) => {
  const id = String(item.id);
  if (approvedPeriodItems.value.some((a) => String(a.id) === id)) return REPORT_STATE.APPROVED;
  if (rejectedPeriodItems.value.some((r) => String(r.id) === id)) return REPORT_STATE.REJECTED;
  if (pendingPeriodItems.value.some((p) => String(p.id) === id)) return REPORT_STATE.PENDING;
  return REPORT_STATE.SUBMITTED;
};

const submitQueueItem = async (item, fillTime = Date.now()) => {
  const auditState = getQueueItemAuditState(item);
  if (auditState === REPORT_STATE.APPROVED || auditState === REPORT_STATE.REJECTED) {
    await submitAssetEdit(
      item,
      { ...buildMonthlyPatch(item), fill_time: fillTime },
      { auditorComment: '月度上报修改送审' }
    );
    return;
  }
  await updateContent({
    content: buildContentPayload(item, { fill_time: fillTime }),
    columnId: COLUMN_ID,
    modelId: MODEL_ID,
  });
  await updateAudit({
    id: item.id,
    columnId: COLUMN_ID,
    state: REPORT_STATE.PENDING,
  });
};

const handleSubmitReport = async () => {
  if (submitting.value || isReportLocked.value) return;
  if (!validateQueue()) return;
  if (!(await showConfirm('确认提交？提交后进入审核'))) return;

  submitting.value = true;
  const fillTime = Date.now();
  try {
    await Promise.all(monthlyQueue.value.map((item) => submitQueueItem(item, fillTime)));

    selectedIds.value = [];
    await enterpriseStore.refreshReportProgress({ skipSubmitted: true });
    await enterpriseStore.refreshStates([REPORT_STATE.SUBMITTED]);
    mergeQueueFromBackend();
    syncQueueAuditState();
    persistQueue();
    await notificationStore.syncAfterReportChange();
    showSuccess('提交成功，进入审核');
  } catch (e) {
    console.log('提交上报异常：', e);
    showError(e?.message || e?.msg || '提交失败，请稍后重试');
  } finally {
    submitting.value = false;
  }
};

const clearQueueStorage = () => {
  try {
    localStorage.removeItem(queueStorageKey.value);
  } catch (e) {
    console.log('清单清除失败：', e);
  }
};

/** 本账期审核已通过：清空清单及 localStorage */
const shouldClearQueueAfterApproval = () => {
  if (pendingPeriodItems.value.length > 0) return false;
  if (rejectedPeriodItems.value.length > 0) return false;
  if (monthlyQueue.value.length > 0) {
    return queueAllApproved.value;
  }
  return approvedPeriodItems.value.length > 0 && getPersistedQueueState() !== 'missing';
};

const resetMonthlyQueueAfterApproval = () => {
  monthlyQueue.value = [];
  monthlyDrafts.value = {};
  selectedIds.value = [];
  reportLocked.value = false;
  clearQueueStorage();
};

const refreshMonthlyQueueState = () => {
  syncMonthlyQueue();
  if (shouldClearQueueAfterApproval()) {
    resetMonthlyQueueAfterApproval();
    return;
  }
  syncQueueAuditState();
  persistQueue();
};

watch(
  () => parseManageRoute(route).tab,
  (tab) => {
    if (tab !== 'archive') return;
    if (monthlySub.value === 'history') loadHistoryData();
    else loadReportingState();
  },
  { immediate: true },
);

const loadReportingState = async ({ resetQueue = false } = {}) => {
  if (resetQueue) {
    await enterpriseStore.refreshReportProgress({ skipSubmitted: true });
    await enterpriseStore.refreshStates([REPORT_STATE.SUBMITTED]);
  } else {
    await enterpriseStore.ensureReportProgress({ skipSubmitted: true });
    await enterpriseStore.ensureState(REPORT_STATE.SUBMITTED);
  }

  if (resetQueue) {
    monthlyQueue.value = [];
    monthlyDrafts.value = {};
    selectedIds.value = [];
    reportLocked.value = false;
    clearQueueStorage();
    return;
  }

  refreshMonthlyQueueState();
};

const mapHistoryRecord = (record, status, statusType, auditStatus) => ({
  ...record,
  status,
  statusType,
  auditTrail: buildAuditTrail(record, auditStatus),
});

/** 同一批上报共用 fill_time，归一化后作为批次 key */
const normalizeSubmissionTime = (val) => {
  if (val == null || val === '') return '';
  const n = Number(val);
  if (Number.isFinite(n) && n > 1e11) return String(Math.floor(n));
  const d = new Date(val);
  return Number.isNaN(d.getTime()) ? String(val).trim() : String(d.getTime());
};

const getSubmissionBatchKey = (item) => {
  const fillTime = item?.fill_time;
  if (fillTime == null || fillTime === '') return `item-${item.id}`;
  return normalizeSubmissionTime(fillTime);
};

/** 按每次批量上报（fill_time）整合，同批多条资产合并为一条历史记录 */
const buildHistoryRecordsFromList = (items, status, statusType, auditStatus) => {
  const group = currentManageGroup.value;
  const fallbackPeriod = currentPeriod.value;
  const map = new Map();

  items.forEach((item) => {
    if (normalizeGroupName(item.c_ssqpjt) !== group) return;

    const period = extractReportMonth(item) || extractPeriod(item, fallbackPeriod);
    const qingpuGroup = normalizeGroupName(item.c_ssqpjt);
    const fillTime = String(item?.fill_time ?? '');
    const auditTime = String(getAuditTime(item) ?? '');
    const batchKey = `${period}|${qingpuGroup}|${getSubmissionBatchKey(item)}|${status}`;

    if (!map.has(batchKey)) {
      map.set(batchKey, {
        id: batchKey,
        period,
        group: item.c_ssjt || qingpuGroup || '暂无',
        qingpuGroup,
        billNo: buildBillNo(period, qingpuGroup),
        submittedAt: formatDateTime(item?.fill_time ?? getFillTime(item)),
        reporter: getReporter(item),
        items: [],
        sortKey: auditTime || fillTime || period,
      });
    }

    const record = map.get(batchKey);
    record.items.push(item);
    const time = auditTime || fillTime;
    if (time >= (record.sortKey || '')) {
      record.sortKey = time;
      record.submittedAt = formatDateTime(item?.fill_time ?? getFillTime(item));
      record.reporter = getReporter(item);
    }
  });

  return [...map.values()]
    .sort((a, b) => (b.sortKey || b.period).localeCompare(a.sortKey || a.period))
    .map((record) => {
      const row = {
        ...record,
        count: record.items.length,
        area: sumBuildAreaWan(record.items),
      };
      delete row.sortKey;
      return mapHistoryRecord(row, status, statusType, auditStatus);
    });
};

const historySourceRows = computed(() => {
  const pending = buildHistoryRecordsFromList(
    enterpriseStore.pendingList,
    '审核中',
    'orange',
    'pending'
  );
  const approved = buildHistoryRecordsFromList(
    enterpriseStore.approvedList,
    '已通过',
    'green',
    'passed'
  );
  const rejected = buildHistoryRecordsFromList(
    enterpriseStore.rejectedList,
    '已驳回',
    'red',
    'rejected'
  );
  return [...pending, ...approved, ...rejected].sort((a, b) =>
    (b.submittedAt || b.period).localeCompare(a.submittedAt || a.period)
  );
});

const periodOptions = computed(() => {
  const periods = new Set(historySourceRows.value.map((row) => row.period).filter(Boolean));
  return [
    { text: '全部', value: '全部' },
    ...[...periods].sort().reverse().map((p) => ({ text: p, value: p })),
  ];
});

const statusOptions = [
  { text: '全部', value: '全部' },
  { text: '审核中', value: '审核中' },
  { text: '已通过', value: '已通过' },
  { text: '已驳回', value: '已驳回' },
];

const historyColumns = [
  { key: 'period', label: '上报月份', width: '120px' },
  { key: 'group', label: '所属集团', width: '200px' },
  { key: 'billNo', label: '上报单据编号', width: '180px' },
  { key: 'submittedAt', label: '填报时间', width: '160px' },
  { key: 'reporter', label: '填报人', width: '100px' },
  { key: 'status', label: '审批状态', width: '120px' },
  { key: 'action', label: '操作', width: '180px' },
];

const HISTORY_EXPORT_COLUMNS = [
  { key: 'period', label: '上报月份' },
  { key: 'group', label: '所属集团' },
  { key: 'billNo', label: '上报单据编号' },
  { key: 'submittedAt', label: '填报时间' },
  { key: 'reporter', label: '填报人' },
  { key: 'status', label: '审批状态' },
  { key: 'count', label: '资产条数' },
  { key: 'area', label: '建筑面积合计（万㎡）' },
];

const filteredHistoryRows = computed(() => {
  const kw = histReporter.value.trim();
  return historySourceRows.value.filter((row) => {
    if (histPeriod.value !== '全部' && row.period !== histPeriod.value) return false;
    if (histStatus.value !== '全部' && row.status !== histStatus.value) return false;
    if (kw && !row.reporter.includes(kw)) return false;
    return true;
  });
});

const loadHistoryData = () => enterpriseStore.ensureReportProgress({ skipSubmitted: true });

const formatReportMonthForExport = (period) => {
  const match = String(period ?? '').match(/^(\d{4})-(\d{2})$/);
  if (!match) return period ?? '';
  return `${match[1]}年${Number(match[2])}月`;
};

const handleHistExport = () => {
  const result = exportTableExcel({
    columns: HISTORY_EXPORT_COLUMNS,
    rows: filteredHistoryRows.value.map((row) => ({
      ...row,
      period: formatReportMonthForExport(row.period),
    })),
    filenameBase: '往期上报报表',
  });

  if (!result.ok) {
    showWarning('当前筛选结果为空，无法导出');
    return;
  }

  showSuccess(`已导出 ${result.count} 条记录（${result.filename}）`);
};

const handleHistDetail = (row) => {
  histDetailRecord.value = row;
  showHistDetail.value = true;
};

const handleHistAudit = (row) => {
  histAuditRecord.value = row;
  showHistAudit.value = true;
};

const resetHistoryFilters = () => {
  histPeriod.value = '全部';
  histStatus.value = '全部';
  histReporter.value = '';
  if (route.query.period || route.query.status) {
    router.replace(buildManageRoute({ tab: 'archive', sub: 'history' }));
  }
};

watch(monthlySub, (tab) => {
  if (parseManageRoute(route).tab !== 'archive') return;
  if (tab === 'history') {
    loadHistoryData();
  } else {
    loadReportingState();
  }
});

const applyRouteSubNav = () => {
  const { tab, sub, period, status } = parseManageRoute(route);
  if (tab !== 'archive') return;

  if (sub !== 'history') {
    monthlySub.value = 'current';
    return;
  }

  monthlySub.value = 'history';
  const nextPeriod = period ? String(period) : '全部';
  const nextStatus =
    status && ['审核中', '已通过', '已驳回'].includes(String(status)) ? String(status) : '全部';

  histPeriod.value = nextPeriod;
  histStatus.value = nextStatus;
  loadHistoryData();
};

const switchArchiveSub = (sub) => {
  if (sub === monthlySub.value) return;
  router.replace(buildManageRoute({ tab: 'archive', sub }));
};

watch(() => route.fullPath, applyRouteSubNav, { immediate: true });

watch(
  () => [currentManageGroup.value, currentEnterprise.value],
  () => {
    if (monthlySub.value === 'current') {
      loadReportingState({ resetQueue: true });
    }
  }
);

watch(
  () => [
    enterpriseStore.pendingList.length,
    enterpriseStore.rejectedList.length,
    enterpriseStore.approvedList.length,
  ],
  () => {
    if (monthlySub.value !== 'current') return;
    refreshMonthlyQueueState();
  }
);
</script>

<style scoped>
.manage-page {
  width: 100%;
  max-width: var(--content-max-width);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.breadcrumb {
  font-family: var(--font-regular);
  font-size: 13px;
  color: var(--color-text-secondary);
  margin: 0;
}

.breadcrumb span {
  color: var(--color-accent);
  font-weight: 500;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.page-title {
  font-family: var(--font-semibold);
  font-size: 20px;
  font-weight: 600;
  color: var(--color-text-primary);
  margin: 0;
}

.sub-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.period-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 20px;
  border-radius: var(--radius-card);
  background: var(--color-surface);
  border: 1px solid var(--color-accent-border);
}

.flow-stepper {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0;
  padding: 8px 0 4px;
  overflow-x: auto;
}

.flow-stepper__node {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  min-width: 72px;
}

.flow-stepper__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid rgba(152, 162, 179, 0.5);
  background: var(--color-surface);
  box-sizing: border-box;
}

.flow-stepper__dot--done {
  border-color: var(--color-accent);
  background: var(--color-accent);
}

.flow-stepper__dot--active {
  border-color: rgba(255, 140, 0, 1);
  background: rgba(255, 140, 0, 1);
  box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.18);
}

.flow-stepper__dot--passed {
  border-color: var(--color-success);
  background: var(--color-success);
}

.flow-stepper__dot--rejected {
  border-color: var(--color-danger);
  background: var(--color-danger);
}

.flow-stepper__dot--future {
  border-color: rgba(152, 162, 179, 0.5);
  background: var(--color-surface);
}

.flow-stepper__line {
  flex: 1 1 auto;
  height: 2px;
  min-width: 24px;
  margin-top: 5px;
  background: rgba(152, 162, 179, 0.35);
}

.flow-stepper__line--done {
  background: var(--color-accent-strong);
}

.flow-stepper__label {
  font-family: var(--font-regular);
  font-size: 12px;
  color: var(--color-text-secondary);
  text-align: center;
  white-space: nowrap;
}

.period-notice {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: rgba(255, 204, 51, 0.12);
  border: 1px solid rgba(255, 204, 51, 0.35);
  font-family: var(--font-regular);
  font-size: 13px;
  color: rgba(120, 90, 0, 1);
}

.period-notice--warn {
  background: rgba(255, 79, 52, 0.08);
  border-color: rgba(255, 79, 52, 0.25);
  color: rgba(180, 50, 30, 1);
}

.muted {
  color: rgba(152, 162, 179, 1);
  font-size: 13px;
}

.status-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: var(--radius-card);
  background: var(--color-accent-hover);
  border: 1px solid var(--color-accent-border);
  font-family: var(--font-regular);
  font-size: 13px;
  color: var(--color-text-body);
}

.panel {
  padding: 20px;
  border-radius: var(--radius-card);
  background: var(--color-surface);
  border: 1px solid var(--color-accent-border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.panel-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.panel-hint {
  font-family: var(--font-regular);
  font-size: 12px;
  color: var(--color-text-secondary);
  margin: 0;
}

.action-row,
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.filter-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-regular);
  font-size: 14px;
  color: var(--color-text-body);
}

.filter-item input {
  height: 36px;
  padding: 0 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-input-border);
  font-family: var(--font-regular);
  font-size: 14px;
  min-width: 140px;
}

.data-table {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-x: auto;
}

.data-table__header,
.data-table__row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 42px;
  min-width: max-content;
}

.data-table__header {
  background: var(--color-table-head);
  border-radius: 2px;
  font-family: var(--font-medium);
  font-weight: 500;
  font-size: 14px;
  color: var(--color-text-secondary);
}

.data-table__row {
  font-family: var(--font-regular);
  font-size: 14px;
  color: var(--color-text-data);
}

.data-table__empty {
  padding: 24px;
  text-align: center;
  font-family: var(--font-regular);
  font-size: 14px;
  color: var(--color-text-secondary);
}

.data-table__header span,
.data-table__row span {
  flex-shrink: 0;
}

.status-tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
}

.status-tag--orange {
  background: rgba(255, 204, 51, 0.2);
  color: rgba(180, 120, 0, 1);
}

.status-tag--green {
  background: rgba(104, 221, 169, 0.25);
  color: var(--color-success);
}

.status-tag--red {
  background: rgba(255, 79, 52, 0.12);
  color: var(--color-danger);
}

.link-btn {
  border: none;
  background: none;
  color: var(--color-accent);
  cursor: pointer;
  font-family: var(--font-regular);
  font-size: 14px;
  padding: 0;
  margin-right: 8px;
}

.link-btn:last-child {
  margin-right: 0;
}

:deep(.nav-tab-item--disabled) {
  opacity: 0.6;
  pointer-events: none;
  cursor: not-allowed;
}
</style>
