<template>
  <div class="detail-query-container">
    <div class="query-page-shell">
      <div class="shell-sidebar">
        <div class="shell-panel-title">筛选条件</div>
        <el-form label-position="top" class="filter-form">
          <el-form-item label="交易时间">
            <el-date-picker
              v-model="dateRange"
              class="filter-control"
              type="datetimerange"
              value-format="yyyy-MM-dd HH:mm:ss"
              range-separator="至"
              start-placeholder="开始时间"
              end-placeholder="结束时间"
              unlink-panels
            />
          </el-form-item>

          <el-form-item label="本方主体">
            <el-select
              v-model="queryParams.ourSubjects"
              class="filter-control"
              multiple
              filterable
              collapse-tags
              clearable
              :loading="optionsLoading"
              placeholder="请选择本方主体"
            >
              <el-option
                v-for="item in optionData.ourSubjectOptions"
                :key="`subject-${item.value}`"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>

          <el-form-item label="本方银行">
            <el-select
              v-model="queryParams.ourBanks"
              class="filter-control"
              multiple
              filterable
              collapse-tags
              clearable
              :loading="optionsLoading"
              placeholder="请选择本方银行"
            >
              <el-option
                v-for="item in optionData.ourBankOptions"
                :key="`bank-${item.value}`"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>

          <el-form-item label="本方账号">
            <el-select
              v-model="queryParams.ourAccounts"
              class="filter-control"
              multiple
              filterable
              collapse-tags
              clearable
              :loading="optionsLoading"
              placeholder="请选择本方账号"
            >
              <el-option
                v-for="item in optionData.ourAccountOptions"
                :key="`account-${item.value}`"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>

          <el-form-item label="金额区间">
            <div class="amount-range">
              <el-input
                v-model="queryParams.amountMin"
                placeholder="最小金额"
                clearable
              />
              <span class="amount-separator">-</span>
              <el-input
                v-model="queryParams.amountMax"
                placeholder="最大金额"
                clearable
              />
            </div>
          </el-form-item>

          <el-form-item>
            <div class="filter-item-header">
              <span class="filter-item-label">对方名称</span>
              <el-checkbox
                v-model="queryParams.counterpartyNameEmpty"
                class="empty-checkbox"
              >
                匹配空值
              </el-checkbox>
            </div>
            <el-input
              v-model="queryParams.counterpartyName"
              placeholder="请输入对方名称"
              clearable
            />
          </el-form-item>

          <el-form-item>
            <div class="filter-item-header">
              <span class="filter-item-label">对方账户</span>
              <el-checkbox
                v-model="queryParams.counterpartyAccountEmpty"
                class="empty-checkbox"
              >
                匹配空值
              </el-checkbox>
            </div>
            <el-input
              v-model="queryParams.counterpartyAccount"
              placeholder="请输入对方账户"
              clearable
            />
          </el-form-item>

          <el-form-item>
            <div class="filter-item-header">
              <span class="filter-item-label">摘要</span>
              <el-checkbox v-model="queryParams.userMemoEmpty" class="empty-checkbox">
                匹配空值
              </el-checkbox>
            </div>
            <el-input
              v-model="queryParams.userMemo"
              placeholder="请输入摘要关键词"
              clearable
            />
          </el-form-item>

          <div class="filter-actions">
            <el-button size="small" type="primary" @click="handleQuery">查询</el-button>
            <el-button size="small" plain @click="resetQuery">重置</el-button>
          </div>
        </el-form>
      </div>

      <div class="shell-main">
        <div class="shell-header">
          <div class="shell-title-group">
            <span class="shell-title">流水明细查询</span>
            <el-radio-group
              v-model="resultMode"
              class="result-mode-switch"
              size="small"
              @change="handleResultModeChange"
            >
              <el-radio-button label="statement">流水明细</el-radio-button>
              <el-radio-button label="counterparty">对手方</el-radio-button>
            </el-radio-group>
          </div>
          <el-button
            v-if="resultMode === 'statement'"
            size="small"
            type="primary"
            plain
            :disabled="total === 0"
            @click="handleExport"
          >
            导出流水
          </el-button>
        </div>
        <el-alert
          v-if="resultMode === 'statement' && prefillTip"
          :closable="false"
          class="prefill-alert"
          show-icon
          type="info"
          :title="prefillTip"
        />

        <el-tabs v-model="activeTab" class="result-tabs" @tab-click="handleTabChange">
          <el-tab-pane label="全部" name="all" />
          <el-tab-pane label="流入" name="in" />
          <el-tab-pane label="流出" name="out" />
        </el-tabs>

        <div class="result-card">
          <el-alert
            v-if="resultMode === 'statement' && listError"
            :closable="false"
            class="result-alert"
            show-icon
            title="流水明细加载失败，请稍后重试"
            type="error"
          />
          <el-alert
            v-if="resultMode === 'counterparty' && counterpartyError"
            :closable="false"
            class="result-alert"
            show-icon
            title="对手方加载失败，请稍后重试"
            type="error"
          />

          <el-table
            v-if="resultMode === 'statement'"
            v-loading="loading"
            :data="list"
            class="result-table"
            @sort-change="handleSortChange"
          >
            <template slot="empty">
              <el-empty
                :image-size="96"
                description="当前筛选条件下暂无流水明细"
              />
            </template>
            <el-table-column
              label="交易时间"
              prop="trxDate"
              min-width="180"
              sortable="custom"
            />
            <el-table-column label="本方账户" min-width="220">
              <template slot-scope="scope">
                <div class="multi-line-cell">
                  <div class="primary-text">{{ formatField(scope.row.leAccountNo) }}</div>
                  <div class="secondary-text">{{ formatField(scope.row.leAccountName) }}</div>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="对方账户" min-width="220">
              <template slot-scope="scope">
                <div class="multi-line-cell">
                  <div class="primary-text">
                    {{ formatField(scope.row.customerAccountName) }}
                  </div>
                  <div class="secondary-text">
                    {{ formatField(scope.row.customerAccountNo) }}
                  </div>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="摘要 / 交易类型" min-width="200">
              <template slot-scope="scope">
                <div class="multi-line-cell">
                  <div class="primary-text">{{ formatField(scope.row.userMemo) }}</div>
                  <div class="secondary-text">{{ formatField(scope.row.cashType) }}</div>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              label="交易金额"
              prop="displayAmount"
              width="120"
              align="right"
              sortable="custom"
            >
              <template slot-scope="scope">
                <span
                  class="amount-text"
                  :class="scope.row.displayAmount >= 0 ? 'amount-in' : 'amount-out'"
                >
                  {{ formatAmount(scope.row.displayAmount) }}
                </span>
              </template>
            </el-table-column>
            <el-table-column label="异常标签" min-width="220">
              <template slot-scope="scope">
                <div v-if="scope.row.hitTags && scope.row.hitTags.length" class="hit-tag-list">
                  <el-tag
                    v-for="(tag, index) in scope.row.hitTags"
                    :key="`${scope.row.bankStatementId}-tag-${index}`"
                    size="mini"
                    :type="mapRiskLevelToTagType(tag.riskLevel)"
                    effect="plain"
                  >
                    {{ tag.ruleName }}
                  </el-tag>
                </div>
                <span v-else class="empty-text">-</span>
              </template>
            </el-table-column>
            <el-table-column label="详情" width="100" fixed="right" align="center">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="handleViewDetail(scope.row)">
                  详情
                </el-button>
              </template>
            </el-table-column>
          </el-table>

          <el-table
            v-else
            v-loading="loading"
            :data="counterpartyList"
            class="result-table counterparty-table"
            @sort-change="handleCounterpartySortChange"
          >
            <template slot="empty">
              <el-empty
                :image-size="96"
                description="当前筛选条件下暂无对手方"
              />
            </template>
            <el-table-column
              label="对手方名称"
              prop="customerAccountName"
              min-width="220"
              :formatter="formatCounterpartyNameColumn"
            />
            <el-table-column
              label="流入合计"
              prop="inAmount"
              width="150"
              align="right"
              sortable="custom"
            >
              <template slot-scope="scope">
                <div class="amount-stack">
                  <span class="amount-text amount-in">{{ formatAmount(scope.row.inAmount) }}</span>
                  <span class="secondary-text">{{ formatCount(scope.row.inCount) }} 笔</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              label="流出合计"
              prop="outAmount"
              width="150"
              align="right"
              sortable="custom"
            >
              <template slot-scope="scope">
                <div class="amount-stack">
                  <span class="amount-text amount-out">{{ formatAmount(scope.row.outAmount) }}</span>
                  <span class="secondary-text">{{ formatCount(scope.row.outCount) }} 笔</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              label="总交易额"
              prop="totalAmount"
              width="150"
              align="right"
              sortable="custom"
            >
              <template slot-scope="scope">
                <div class="amount-stack">
                  <span class="amount-text">{{ formatAmount(scope.row.totalAmount) }}</span>
                  <span class="secondary-text">{{ formatCount(scope.row.totalCount) }} 笔</span>
                </div>
              </template>
            </el-table-column>
            <el-table-column
              label="最近交易时间"
              prop="latestTrxDate"
              min-width="170"
              sortable="custom"
            >
              <template slot-scope="scope">
                {{ formatField(scope.row.latestTrxDate) }}
              </template>
            </el-table-column>
          </el-table>

          <pagination
            v-show="currentTotal > 0"
            :total="currentTotal"
            :page.sync="queryParams.pageNum"
            :limit.sync="queryParams.pageSize"
            @pagination="handlePageChange"
          />
        </div>
      </div>
    </div>

    <el-dialog
      :visible.sync="detailVisible"
      append-to-body
      custom-class="detail-dialog"
      width="980px"
      @close="closeDetailDialog"
    >
      <template slot="title">
        <div class="detail-dialog-title">
          <span>流水详情</span>
          <el-button
            class="evidence-corner-btn"
            size="mini"
            plain
            :disabled="detailLoading || !buildFlowEvidenceFingerprint(detailData)"
            @click="handleAddEvidence"
          >
            加入证据库
          </el-button>
        </div>
      </template>
      <div v-loading="detailLoading" class="detail-dialog-body">
        <div class="detail-overview-grid">
          <div class="detail-field">
            <div class="detail-label">交易时间</div>
            <div class="detail-value">{{ formatField(detailData.trxDate) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">交易金额</div>
            <div class="detail-value amount-text" :class="getAmountClass(detailData.displayAmount)">
              {{ formatSignedAmount(detailData.displayAmount) }}
            </div>
          </div>
          <div class="detail-field">
            <div class="detail-label">交易后余额</div>
            <div class="detail-value">{{ formatAmount(detailData.amountBalance) }}</div>
          </div>

          <div class="detail-field">
            <div class="detail-label">本方主体</div>
            <div class="detail-value">{{ formatField(detailData.leAccountName) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">本方账号</div>
            <div class="detail-value">{{ formatField(detailData.leAccountNo) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">本方银行</div>
            <div class="detail-value">{{ formatField(detailData.bank) }}</div>
          </div>

          <div class="detail-field">
            <div class="detail-label">对方名称</div>
            <div class="detail-value">{{ formatCounterpartyName(detailData) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">对方账户</div>
            <div class="detail-value">{{ formatField(detailData.customerAccountNo) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">对方银行</div>
            <div class="detail-value">{{ formatField(detailData.customerBank) }}</div>
          </div>

          <div class="detail-field">
            <div class="detail-label">摘要</div>
            <div class="detail-value">{{ formatField(detailData.userMemo) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">交易类型</div>
            <div class="detail-value">{{ formatField(detailData.cashType) }}</div>
          </div>
          <div class="detail-field">
            <div class="detail-label">银行摘要</div>
            <div class="detail-value">{{ formatField(detailData.bankComments) }}</div>
          </div>

          <div class="detail-field detail-field--full">
            <div class="detail-label">原始文件</div>
            <div class="detail-file-block">
              <i class="el-icon-document detail-file-icon"></i>
              <div class="detail-file-meta">
                <div class="detail-file-name">{{ formatOriginalFileName(detailData) }}</div>
                <div class="detail-file-time">
                  上传时间：{{ formatOriginalFileUploadTime(detailData) }}
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="detail-hit-tag-section">
          <div class="detail-section-title">命中异常标签</div>
          <div
            v-if="detailData.hitTags && detailData.hitTags.length"
            class="detail-hit-tag-items"
          >
            <div
              v-for="(tag, index) in detailData.hitTags"
              :key="`detail-tag-${index}`"
              class="detail-hit-tag-item"
            >
              <div class="detail-hit-tag-header">
                <span class="detail-hit-tag-name">{{ formatField(tag.ruleName) }}</span>
                <el-tag size="mini" :type="mapRiskLevelToTagType(tag.riskLevel)" effect="plain">
                  {{ formatRiskLevel(tag.riskLevel) }}
                </el-tag>
              </div>
              <div class="detail-hit-tag-reason">{{ formatField(tag.reasonDetail) }}</div>
            </div>
          </div>
          <div v-else class="detail-hit-tag-empty">当前流水未命中异常标签</div>
        </div>
      </div>
      <div slot="footer" class="detail-dialog-footer">
        <el-button @click="closeDetailDialog">取消</el-button>
        <el-button type="primary" @click="closeDetailDialog">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { parseTime } from "@/utils/ruoyi";
import {
  listBankStatement,
  listBankStatementCounterparties,
  getBankStatementOptions,
  getBankStatementDetail,
} from "@/api/ccdiProjectBankStatement";
import { buildFlowEvidenceFingerprint, buildFlowEvidenceSnapshot } from "@/utils/ccdiEvidence";

const TAB_MAP = {
  all: "all",
  in: "in",
  out: "out",
};

const SORT_MAP = {
  trxDate: "trxDate",
  displayAmount: "amount",
};

const COUNTERPARTY_SORT_MAP = {
  inAmount: "inAmount",
  outAmount: "outAmount",
  totalAmount: "totalAmount",
  totalCount: "totalCount",
  latestTrxDate: "latestTrxDate",
};

const createDefaultQueryParams = (projectId) => ({
  projectId,
  pageNum: 1,
  pageSize: 10,
  tabType: "all",
  transactionStartTime: "",
  transactionEndTime: "",
  counterpartyName: "",
  counterpartyNameEmpty: false,
  userMemo: "",
  userMemoEmpty: false,
  ourSubjects: [],
  ourBanks: [],
  ourAccounts: [],
  amountMin: "",
  amountMax: "",
  counterpartyAccount: "",
  counterpartyAccountEmpty: false,
  orderBy: "trxDate",
  orderDirection: "desc",
});

const createEmptyOptionData = () => ({
  ourSubjectOptions: [],
  ourBankOptions: [],
  ourAccountOptions: [],
});

const normalizeHitTags = (hitTags) => (Array.isArray(hitTags) ? hitTags : []);

const createEmptyDetailData = () => ({
  bankStatementId: "",
  projectId: "",
  trxDate: "",
  currency: "",
  leAccountNo: "",
  leAccountName: "",
  customerAccountName: "",
  customerAccountNo: "",
  customerBank: "",
  customerReference: "",
  userMemo: "",
  bankComments: "",
  bankTrxNumber: "",
  bank: "",
  cashType: "",
  amountDr: "",
  amountCr: "",
  amountBalance: "",
  displayAmount: "",
  trxFlag: "",
  trxType: "",
  exceptionType: "",
  internalFlag: "",
  paymentMethod: "",
  cretNo: "",
  createDate: "",
  originalFileName: "",
  uploadTime: "",
  sourceFileName: "",
  fileName: "",
  hitTags: [],
});

export default {
  name: "DetailQuery",
  props: {
    projectId: {
      type: [String, Number],
      default: null,
    },
    projectInfo: {
      type: Object,
      default: () => ({
        projectName: "",
        updateTime: "",
        projectStatus: "0",
      }),
    },
    detailQueryPrefill: {
      type: Object,
      default: null,
    },
  },
  data() {
    return {
      loading: false,
      optionsLoading: false,
      detailLoading: false,
      detailVisible: false,
      resultMode: "statement",
      activeTab: "all",
      dateRange: [],
      list: [],
      total: 0,
      counterpartyList: [],
      counterpartyTotal: 0,
      counterpartyError: "",
      listError: "",
      prefillTip: "",
      detailData: createEmptyDetailData(),
      queryParams: createDefaultQueryParams(this.projectId),
      optionData: createEmptyOptionData(),
    };
  },
  created() {
    this.getList();
    this.getOptions();
  },
  computed: {
    currentTotal() {
      return this.resultMode === "counterparty" ? this.counterpartyTotal : this.total;
    },
  },
  watch: {
    dateRange(value) {
      this.queryParams.transactionStartTime = value && value[0] ? value[0] : "";
      this.queryParams.transactionEndTime = value && value[1] ? value[1] : "";
    },
    projectId() {
      this.syncProjectId();
      this.getOptions();
      this.getList();
    },
    detailQueryPrefill: {
      immediate: true,
      deep: true,
      handler(value) {
        this.applyDetailQueryPrefill(value);
      },
    },
  },
  methods: {
    buildFlowEvidenceFingerprint,
    async getList() {
      this.syncProjectId();
      if (!this.queryParams.projectId) {
        this.list = [];
        this.total = 0;
        this.counterpartyList = [];
        this.counterpartyTotal = 0;
        this.listError = "";
        this.counterpartyError = "";
        return;
      }

      this.loading = true;
      try {
        if (this.resultMode === "counterparty") {
          await this.getCounterpartyList();
          return;
        }
        const res = await listBankStatement(this.queryParams);
        this.list = (res.rows || []).map((item) => ({
          ...item,
          hitTags: normalizeHitTags(item && item.hitTags),
        }));
        this.total = res.total || 0;
        this.listError = "";
      } catch (error) {
        this.list = [];
        this.total = 0;
        this.listError = "加载流水明细失败";
        console.error("加载流水明细失败", error);
      } finally {
        this.loading = false;
      }
    },
    async getCounterpartyList() {
      try {
        const res = await listBankStatementCounterparties(this.queryParams);
        this.counterpartyList = res.rows || [];
        this.counterpartyTotal = res.total || 0;
        this.counterpartyError = "";
      } catch (error) {
        this.counterpartyList = [];
        this.counterpartyTotal = 0;
        this.counterpartyError = "加载对手方失败";
        console.error("加载对手方失败", error);
      }
    },
    async getOptions() {
      this.syncProjectId();
      if (!this.queryParams.projectId) {
        this.optionData = createEmptyOptionData();
        return;
      }

      this.optionsLoading = true;
      try {
        const res = await getBankStatementOptions(this.queryParams.projectId);
        const data = res.data || {};
        this.optionData = {
          ourSubjectOptions: data.ourSubjectOptions || [],
          ourBankOptions: data.ourBankOptions || [],
          ourAccountOptions: data.ourAccountOptions || [],
        };
      } catch (error) {
        this.optionData = createEmptyOptionData();
        console.error("加载流水筛选项失败", error);
      } finally {
        this.optionsLoading = false;
      }
    },
    syncProjectId() {
      this.queryParams.projectId = this.projectId;
      this.queryParams.tabType = TAB_MAP[this.activeTab] || "all";
    },
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.syncProjectId();
      this.getList();
    },
    resetQuery() {
      this.activeTab = "all";
      this.dateRange = [];
      this.queryParams = createDefaultQueryParams(this.projectId);
      this.prefillTip = "";
      this.syncProjectId();
      this.getOptions();
      this.getList();
    },
    applyDetailQueryPrefill(value) {
      if (!value || !Array.isArray(value.ourCertNos) || !value.ourCertNos.length) {
        return;
      }
      this.resultMode = "statement";
      this.activeTab = "all";
      this.dateRange = [];
      this.queryParams = {
        ...createDefaultQueryParams(this.projectId),
        ourCertNos: value.ourCertNos,
      };
      this.prefillTip = `当前查看：${value.title || "外部人员"} 的本方流水`;
      this.syncProjectId();
      this.getList();
    },
    handleResultModeChange(mode) {
      this.queryParams.pageNum = 1;
      if (mode === "counterparty") {
        this.queryParams.orderBy = "totalAmount";
        this.queryParams.orderDirection = "desc";
      } else {
        this.queryParams.orderBy = "trxDate";
        this.queryParams.orderDirection = "desc";
      }
      this.getList();
    },
    handleTabChange(tab) {
      const tabName = tab && tab.name ? tab.name : this.activeTab;
      this.activeTab = tabName;
      this.queryParams.pageNum = 1;
      this.queryParams.tabType = TAB_MAP[tabName] || "all";
      this.getList();
    },
    handleSortChange({ prop, order }) {
      this.queryParams.orderBy = SORT_MAP[prop] || "trxDate";
      this.queryParams.orderDirection = order === "ascending" ? "asc" : "desc";
      if (!order) {
        this.queryParams.orderBy = "trxDate";
        this.queryParams.orderDirection = "desc";
      }
      this.getList();
    },
    handleCounterpartySortChange({ prop, order }) {
      this.queryParams.orderBy = COUNTERPARTY_SORT_MAP[prop] || "totalAmount";
      this.queryParams.orderDirection = order === "ascending" ? "asc" : "desc";
      if (!order) {
        this.queryParams.orderBy = "totalAmount";
        this.queryParams.orderDirection = "desc";
      }
      this.getList();
    },
    handlePageChange(pageInfo) {
      if (typeof pageInfo === "number") {
        this.queryParams.pageNum = pageInfo;
      } else {
        this.queryParams.pageNum = pageInfo.page;
        this.queryParams.pageSize = pageInfo.limit;
      }
      this.getList();
    },
    async handleViewDetail(row) {
      if (!row || !row.bankStatementId) {
        return;
      }

      this.detailVisible = true;
      this.detailLoading = true;
      try {
        const res = await getBankStatementDetail(row.bankStatementId);
        const detail = res.data || {};
        this.detailData = {
          ...createEmptyDetailData(),
          ...detail,
          hitTags: normalizeHitTags(detail.hitTags),
        };
      } catch (error) {
        this.detailData = createEmptyDetailData();
        this.$message.error("加载流水详情失败");
        console.error("加载流水详情失败", error);
      } finally {
        this.detailLoading = false;
      }
    },
    closeDetailDialog() {
      this.detailVisible = false;
      this.detailLoading = false;
      this.detailData = createEmptyDetailData();
    },
    handleAddEvidence() {
      const detail = this.detailData || {};
      const sourceRecordId = buildFlowEvidenceFingerprint(detail);
      const amountText = this.formatSignedAmount(detail.displayAmount);
      const counterparty = this.formatCounterpartyName(detail);
      const hitTagText = Array.isArray(detail.hitTags) && detail.hitTags.length
        ? `，命中${detail.hitTags.map((tag) => tag.ruleName).filter(Boolean).join("、")}标签`
        : "";
      this.$emit("evidence-confirm", {
        evidenceType: "FLOW",
        relatedPersonName: this.resolveFlowRelatedPerson(detail),
        relatedPersonId: detail.cretNo || "",
        evidenceTitle: `${this.resolveFlowRelatedPerson(detail)} / ${this.formatField(detail.leAccountNo)}`,
        evidenceSummary: `${this.formatField(detail.trxDate)}，${this.resolveFlowRelatedPerson(detail)}账户与${counterparty}发生交易，金额${amountText}${hitTagText}。`,
        sourceType: "BANK_STATEMENT",
        sourceRecordId,
        sourcePage: "流水详情",
        snapshotJson: JSON.stringify(buildFlowEvidenceSnapshot(detail)),
      });
    },
    resolveFlowRelatedPerson(detail) {
      return this.formatField(detail.leAccountName) === "-" ? "关联人员" : this.formatField(detail.leAccountName);
    },
    handleExport() {
      if (this.total === 0) {
        return;
      }

      this.download(
        "ccdi/project/bank-statement/export",
        { ...this.queryParams },
        `${this.projectInfo.projectName || "项目"}_流水明细_${Date.now()}.xlsx`
      );
    },
    formatField(value) {
      if (value === null || value === undefined || value === "") {
        return "-";
      }
      return String(value);
    },
    formatDate(value) {
      return value ? parseTime(value, "{y}-{m}-{d} {h}:{i}:{s}") : "-";
    },
    formatAmount(value) {
      if (value === null || value === undefined || value === "") {
        return "-";
      }
      const amount = Number(value);
      if (Number.isNaN(amount)) {
        return "-";
      }
      return amount.toLocaleString("zh-CN", {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      });
    },
    formatCount(value) {
      if (value === null || value === undefined || value === "") {
        return 0;
      }
      const count = Number(value);
      return Number.isNaN(count) ? 0 : count;
    },
    formatSignedAmount(value) {
      if (value === null || value === undefined || value === "") {
        return "-";
      }
      const amount = Number(value);
      if (Number.isNaN(amount)) {
        return "-";
      }
      const text = this.formatAmount(amount);
      return amount > 0 ? `+${text}` : text;
    },
    getAmountClass(value) {
      if (value === null || value === undefined || value === "") {
        return "";
      }
      return Number(value) >= 0 ? "amount-in" : "amount-out";
    },
    formatCounterpartyName(detail) {
      if (!detail) {
        return "-";
      }
      return this.formatField(detail.customerAccountName);
    },
    formatCounterpartyRowName(row) {
      if (!row || row.nameEmpty || !row.customerAccountName) {
        return "为空";
      }
      return this.formatField(row.customerAccountName);
    },
    formatCounterpartyNameColumn(row) {
      return this.formatCounterpartyRowName(row);
    },
    formatOriginalFileName(detail) {
      if (!detail) {
        return "暂无原始文件";
      }
      return (
        detail.originalFileName ||
        detail.sourceFileName ||
        detail.fileName ||
        "暂无原始文件"
      );
    },
    formatOriginalFileUploadTime(detail) {
      if (!detail) {
        return "-";
      }
      return this.formatDate(detail.uploadTime);
    },
    formatRiskLevel(value) {
      const level = String(value || "").toUpperCase();
      if (level === "HIGH") {
        return "高风险";
      }
      if (level === "MEDIUM") {
        return "中风险";
      }
      if (level === "LOW") {
        return "低风险";
      }
      return "未标注";
    },
    mapRiskLevelToTagType(riskLevel) {
      const level = String(riskLevel || "").toUpperCase();
      if (level === "HIGH") {
        return "danger";
      }
      if (level === "MEDIUM") {
        return "warning";
      }
      return "info";
    },
  },
};
</script>

<style lang="scss" scoped>
.detail-query-container {
  padding: 16px;
  background: #fff;
  min-height: 480px;
}

.query-page-shell {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 12px;
}

.detail-dialog-title {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.evidence-corner-btn {
  padding: 4px 9px;
  font-size: 12px;
  color: #5b7fb8;
  border-color: #d6e4f7;
  background: #f8fbff;

  &:hover {
    color: #2474e8;
    border-color: #9fc3ff;
    background: #edf5ff;
  }
}

.shell-sidebar,
.shell-main {
  border: 1px solid #ebeef5;
  border-radius: 4px;
  background: #fff;
}

.shell-sidebar {
  padding: 16px 14px;
}

.shell-main {
  padding: 20px;
}

.shell-panel-title,
.shell-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.shell-title-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.shell-subtitle {
  font-size: 13px;
  color: #909399;
}

.result-mode-switch {
  margin-top: 8px;

  :deep(.el-radio-button__inner) {
    min-width: 82px;
  }
}

.shell-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 20px;
}

.filter-form {
  margin-top: 12px;

  :deep(.el-form-item) {
    margin-bottom: 14px;
  }

  :deep(.el-form-item__label) {
    padding-bottom: 6px;
    line-height: 20px;
    font-size: 13px;
  }
}

.filter-control {
  width: 100%;
}

.filter-item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.filter-item-label {
  font-size: 13px;
  line-height: 20px;
  color: #606266;
}

.empty-checkbox {
  margin-top: 0;
  flex-shrink: 0;
}

:deep(.empty-checkbox .el-checkbox__label) {
  padding-left: 4px;
  font-size: 12px;
  color: #909399;
}

.amount-range {
  display: flex;
  align-items: center;
  gap: 6px;
}

.amount-separator {
  color: #909399;
  font-size: 13px;
}

.filter-actions {
  display: flex;
  gap: 8px;

  .el-button {
    flex: 1;
  }
}

.result-tabs {
  margin-bottom: 16px;
}

.result-card {
  border: none;
  border-radius: 4px;
  overflow: hidden;
}

.result-alert {
  margin: 16px 16px 0;
}

.result-table {
  width: 100%;
}

.multi-line-cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.primary-text {
  color: #303133;
  line-height: 20px;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.secondary-text {
  color: #909399;
  font-size: 12px;
  line-height: 18px;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.hit-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}

.hit-tag-list ::v-deep .el-tag {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.empty-text {
  color: #909399;
  font-size: 13px;
  line-height: 20px;
}

.amount-text {
  font-weight: 600;
}

.amount-stack {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  min-width: 0;
  line-height: 20px;
}

.amount-in {
  color: #67c23a;
}

.amount-out {
  color: #f56c6c;
}

.detail-dialog-body {
  min-height: 280px;
}

.detail-overview-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px 32px;
  margin-bottom: 24px;
}

.detail-field {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.detail-field--full {
  grid-column: 1 / -1;
}

.detail-label {
  font-size: 14px;
  line-height: 20px;
  color: #909399;
}

.detail-value {
  color: #303133;
  line-height: 22px;
  font-size: 16px;
  font-weight: 500;
  word-break: break-all;
}

.detail-file-block {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 2px 0;
}

.detail-file-icon {
  margin-top: 2px;
  font-size: 20px;
  color: #f59a23;
}

.detail-file-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.detail-file-name {
  color: #303133;
  line-height: 22px;
  word-break: break-all;
}

.detail-file-time {
  color: #909399;
  font-size: 12px;
  line-height: 18px;
}

.detail-hit-tag-section {
  border-top: 1px solid #ebeef5;
  padding-top: 24px;
}

.detail-section-title {
  margin-bottom: 16px;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.detail-hit-tag-items {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.detail-hit-tag-item {
  padding: 12px 16px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  background: #fafafa;
}

.detail-hit-tag-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.detail-hit-tag-name {
  color: #303133;
  font-size: 14px;
  font-weight: 600;
  line-height: 22px;
  word-break: break-all;
}

.detail-hit-tag-reason {
  margin-top: 8px;
  color: #606266;
  font-size: 13px;
  line-height: 20px;
  word-break: break-word;
}

.detail-hit-tag-empty {
  color: #909399;
  font-size: 13px;
  line-height: 20px;
}

.detail-dialog-footer {
  display: flex;
  justify-content: center;
  gap: 12px;
}

:deep(.detail-dialog) {
  border-radius: 8px;

  .el-dialog__header {
    padding: 20px 24px;
    border-bottom: 1px solid #ebeef5;
  }

  .el-dialog__title {
    font-size: 20px;
    font-weight: 600;
    color: #303133;
  }

  .el-dialog__body {
    padding: 24px;
  }

  .el-dialog__footer {
    padding: 8px 24px 24px;
  }

  .el-button {
    min-width: 180px;
  }
}

@media (max-width: 992px) {
  .query-page-shell {
    grid-template-columns: 1fr;
  }

  .filter-actions {
    flex-direction: column;
  }

  .detail-overview-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px 24px;
  }
}

@media (max-width: 768px) {
  .detail-query-container {
    padding: 8px;
  }

  .shell-sidebar,
  .shell-main {
    padding: 16px;
  }

  .shell-header {
    flex-direction: column;
  }

  .result-alert {
    margin: 12px 12px 0;
  }

  .detail-overview-grid {
    grid-template-columns: 1fr;
    gap: 18px;
  }

  .detail-dialog-footer {
    flex-direction: column;
  }

  .detail-hit-tag-header {
    flex-direction: column;
    align-items: stretch;
  }

  :deep(.detail-dialog) {
    width: calc(100vw - 24px) !important;
    margin-top: 8vh !important;

    .el-dialog__header,
    .el-dialog__body,
    .el-dialog__footer {
      padding-left: 16px;
      padding-right: 16px;
    }

    .el-button {
      width: 100%;
      min-width: 0;
    }
  }
}
</style>
