<template>
  <div class="upload-data-container">
    <!-- 主内容区 -->
    <div class="main-content">
      <!-- 页面头部 -->
      <div class="content-header">
        <h2 class="content-title">{{ currentMenuTitle }}</h2>
        <div class="header-actions">
          <el-button
            size="small"
            type="primary"
            icon="el-icon-document"
            @click="handleGenerateReport"
          >
            生成报告
          </el-button>
          <el-button
            size="small"
            icon="el-icon-download"
            @click="handleFetchBankInfo"
          >
            拉取本行信息
          </el-button>
        </div>
      </div>

      <!-- 上传模块 -->
      <div class="upload-section">
        <div class="upload-cards">
          <div
            v-for="card in uploadCards"
            :key="card.key"
            class="upload-card"
            :class="{ 'is-disabled': card.disabled }"
          >
            <div class="card-icon">
              <i :class="card.icon"></i>
            </div>
            <div class="card-title">{{ card.title }}</div>
            <div class="card-desc">{{ card.desc }}</div>
            <el-button
              size="small"
              :type="card.uploaded ? 'primary' : ''"
              :icon="card.uploaded ? 'el-icon-view' : 'el-icon-upload2'"
              :plain="!card.uploaded"
              :disabled="card.disabled"
              @click="handleUploadClick(card.key)"
            >
              {{ card.btnText }}
            </el-button>
          </div>
        </div>
      </div>

      <!-- 文件上传记录列表 -->
      <div class="file-list-section">
        <div class="list-toolbar">
          <el-button icon="el-icon-refresh" @click="handleManualRefresh">刷新</el-button>
        </div>

        <el-table :data="fileUploadList" v-loading="listLoading">
          <el-table-column prop="fileName" label="文件名" min-width="200"></el-table-column>
          <el-table-column prop="fileSize" label="文件大小" width="120">
            <template slot-scope="scope">
              {{ formatFileSize(scope.row.fileSize) }}
            </template>
          </el-table-column>
          <el-table-column prop="fileStatus" label="状态" width="120">
            <template slot-scope="scope">
              <el-tag :type="getStatusType(scope.row.fileStatus)" size="small">
                {{ getStatusText(scope.row.fileStatus) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="enterpriseNames" label="主体名称" min-width="150">
            <template slot-scope="scope">
              {{ scope.row.enterpriseNames || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="accountNos" label="主体账号" min-width="180">
            <template slot-scope="scope">
              {{ scope.row.accountNos || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="uploadTime" label="上传时间" width="180">
            <template slot-scope="scope">
              {{ formatUploadTime(scope.row.uploadTime) }}
            </template>
          </el-table-column>
          <el-table-column prop="uploadUser" label="上传人" width="100"></el-table-column>
          <el-table-column label="操作" width="160" fixed="right">
            <template slot-scope="scope">
              <el-button
                v-if="getRowAction(scope.row)"
                type="text"
                @click="handleRowAction(scope.row)"
              >
                {{ getRowAction(scope.row).text }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>

        <el-pagination
          @current-change="handlePageChange"
          :current-page="queryParams.pageNum"
          :page-size="queryParams.pageSize"
          :total="total"
          layout="total, prev, pager, next, jumper"
          style="margin-top: 16px; text-align: right"
        ></el-pagination>
      </div>

      <!-- 数据质量检查
      <div class="quality-check-section">
        <div class="section-header">
          <i class="el-icon-warning-outline warning-icon"></i>
          <span>检查结果</span>
        </div>
        <div class="metrics">
          <div v-for="metric in metrics" :key="metric.key" class="metric-card">
            <div class="metric-title">{{ metric.title }}</div>
            <div class="metric-value" :class="`value-${metric.level}`">
              {{ metric.value }}
            </div>
            <div class="progress-ring-container">
              <svg class="progress-ring" viewBox="0 0 32 32">
                <circle
                  class="progress-ring-bg"
                  cx="16"
                  cy="16"
                  r="14"
                  fill="none"
                  stroke="#f0f0f0"
                  stroke-width="4"
                />
                <circle
                  class="progress-ring-progress"
                  :stroke="getProgressColor(metric.level)"
                  cx="16"
                  cy="16"
                  r="14"
                  fill="none"
                  stroke-width="4"
                  :stroke-dasharray="circumference"
                  :stroke-dashoffset="getProgressOffset(metric.value)"
                  stroke-linecap="round"
                />
              </svg>
            </div>
          </div>
        </div>
      </div> -->
    </div>

    <!-- 上传弹窗 -->
    <el-dialog
      v-if="showUploadDialog"
      :title="uploadDialogTitle"
      :visible.sync="showUploadDialog"
      :close-on-click-modal="false"
      width="500px"
    >
      <el-upload
        class="upload-area"
        drag
        action="#"
        :auto-upload="false"
        :on-change="handleFileChange"
        :file-list="fileList"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">
          支持 {{ uploadFileTypes }} 格式文件
        </div>
      </el-upload>
      <span slot="footer">
        <el-button @click="showUploadDialog = false">取消</el-button>
        <el-button
          type="primary"
          @click="handleConfirmUpload"
          :loading="uploading"
          >确定</el-button
        >
      </span>
    </el-dialog>

    <!-- 名单选择弹窗 -->
    <el-dialog
      :title="'名单库选择'"
      :visible.sync="showNameListDialog"
      width="600px"
    >
      <el-form :model="nameListForm" label-width="100px">
        <el-form-item label="名单类型">
          <el-select v-model="nameListForm.type" placeholder="请选择名单类型">
            <el-option label="黑名单" value="blacklist"></el-option>
            <el-option label="灰名单" value="graylist"></el-option>
            <el-option label="白名单" value="whitelist"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="名单来源">
          <el-select v-model="nameListForm.source" placeholder="请选择名单来源">
            <el-option label="中台管理系统" value="platform"></el-option>
            <el-option label="本地上传" value="local"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <span slot="footer">
        <el-button @click="showNameListDialog = false">取消</el-button>
        <el-button type="primary" @click="handleConfirmNameList"
          >确定</el-button
        >
      </span>
    </el-dialog>

    <el-dialog
      title="拉取本行信息"
      :visible.sync="pullBankInfoDialogVisible"
      :close-on-click-modal="false"
      width="640px"
    >
      <el-form
        class="pull-bank-info-form"
        :model="pullBankInfoForm"
        label-width="100px"
      >
        <el-form-item label="证件号码">
          <el-input
            v-model="pullBankInfoForm.idCardText"
            type="textarea"
            :rows="5"
            placeholder="支持逗号、中文逗号、换行分隔"
          />
          <div class="pull-bank-field-tip">
            支持逗号、中文逗号、换行分隔，文件解析结果会自动合并并去重
          </div>
        </el-form-item>
        <el-form-item label="身份证文件">
          <div class="pull-bank-file-panel">
            <div class="pull-bank-file-actions">
              <el-upload
                class="pull-bank-file-upload"
                action="#"
                :auto-upload="false"
                :limit="1"
                :show-file-list="false"
                :file-list="idCardFileList"
                accept=".xls,.xlsx"
                :on-change="handleIdCardFileChange"
                :on-remove="handleIdCardFileRemove"
              >
                <el-button slot="trigger" size="small" type="primary" plain>
                  选择文件
                </el-button>
              </el-upload>
              <div class="pull-bank-file-tip">
                支持 .xls、.xlsx 文件，解析后自动补充证件号码
              </div>
            </div>
            <div v-if="idCardFileList.length > 0" class="selected-id-card-file">
              <div class="selected-id-card-file__info">
                <i class="el-icon-document"></i>
                <span class="selected-id-card-file__name">
                  {{ idCardFileList[0].name }}
                </span>
              </div>
              <el-button type="text" @click="handleIdCardFileRemove">
                移除
              </el-button>
            </div>
            <div v-if="parsingIdCardFile" class="parse-tip">
              正在解析身份证文件...
            </div>
          </div>
        </el-form-item>
        <el-form-item label="时间跨度">
          <el-date-picker
            class="pull-bank-range-picker"
            v-model="pullBankInfoForm.dateRange"
            type="daterange"
            value-format="yyyy-MM-dd"
            :picker-options="pullBankInfoDatePickerOptions"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
          />
        </el-form-item>
      </el-form>
      <span slot="footer">
        <el-button @click="pullBankInfoDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          :loading="pullBankInfoLoading"
          @click="handleConfirmPullBankInfo"
        >
          确认拉取
        </el-button>
      </span>
    </el-dialog>

    <!-- 批量上传弹窗 -->
    <el-dialog
      title="批量上传流水文件"
      :visible.sync="batchUploadDialogVisible"
      :close-on-click-modal="false"
      width="700px"
    >
      <el-upload
        class="batch-upload-area"
        drag
        action="#"
        multiple
        :auto-upload="false"
        :on-change="handleBatchFileChange"
        :show-file-list="false"
        :file-list="selectedFiles"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">
          支持 PDF、CSV、Excel 格式文件，最多100个文件，单个文件不超过50MB
        </div>
      </el-upload>

      <div v-if="selectedFiles.length > 0" class="selected-files">
        <div class="files-header">
          <span>已选择 {{ selectedFiles.length }} 个文件</span>
        </div>
        <div class="files-list">
          <div
            v-for="(file, index) in selectedFiles"
            :key="index"
            class="file-item"
          >
            <i class="el-icon-document"></i>
            <span class="file-name">{{ file.name }}</span>
            <span class="file-size">{{ formatFileSize(file.size) }}</span>
            <el-button
              type="text"
              icon="el-icon-close"
              @click="handleRemoveFile(index)"
            ></el-button>
          </div>
        </div>
      </div>

      <span slot="footer">
        <el-button @click="batchUploadDialogVisible = false">取消</el-button>
        <el-button
          type="primary"
          :loading="uploadLoading"
          :disabled="selectedFiles.length === 0"
          @click="handleBatchUpload"
          >开始上传</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import {
  getImportStatus,
  getNameListOptions,
  getUploadStatus,
  pullBankInfo,
  parseIdCardFile,
  updateNameListSelection,
  uploadFile,
  batchUploadFiles,
  getFileUploadList,
  getFileUploadStatistics,
  deleteFileUploadRecord,
} from "@/api/ccdiProjectUpload";
import { parseTime } from "@/utils/ruoyi";
import {
  getUploadFileAction,
  getUploadFileStatusText,
  getUploadFileStatusType,
} from "./uploadFileActionRules";

export default {
  name: "UploadData",
  props: {
    projectId: {
      type: [String, Number],
      default: null,
    },
    projectInfo: {
      type: Object,
      default: () => ({
        projectName: "",
        updateTime: "",
        projectStatus: "0",
      }),
    },
  },
  data() {
    return {
      // 加载状态
      loading: false,
      // 当前选中的菜单
      activeMenu: "upload",
      // 当前菜单标题
      currentMenuTitle: "上传数据",
      // 圆环周长
      circumference: 2 * Math.PI * 14,
      // 上传弹窗
      showUploadDialog: false,
      uploadDialogTitle: "",
      uploadFileType: "",
      uploadFileTypes: "",
      fileList: [],
      uploading: false,
      pullBankInfoDialogVisible: false,
      pullBankInfoLoading: false,
      parsingIdCardFile: false,
      idCardFileList: [],
      pullBankInfoForm: {
        idCardText: "",
        dateRange: [],
      },
      // 名单选择弹窗
      showNameListDialog: false,
      nameListForm: {
        type: "",
        source: "platform",
      },
      // 上传状态列表
      uploadStatusList: [],
      // 名单库选项列表
      nameListOptions: [],
      // 侧边栏菜单项
      menuItems: [
        { key: "upload", label: "上传数据", route: "upload" },
        { key: "config", label: "参数配置", route: "config" },
        { key: "overview", label: "结果总览", route: "overview" },
        { key: "special", label: "专项排查", route: "special" },
        { key: "detail", label: "流水明细查询", route: "detail" },
      ],
      // 上传卡片
      uploadCards: [
        {
          key: "transaction",
          title: "流水导入",
          desc: "支持 PDF、CSV、Excel 格式文件上传",
          icon: "el-icon-document",
          btnText: "上传流水",
          uploaded: false,
          disabled: false,
        },
        {
          key: "credit",
          title: "征信导入",
          desc: "支持 HTML 格式征信数据解析",
          icon: "el-icon-s-data",
          btnText: "上传征信",
          uploaded: false,
          disabled: true,
        },
        {
          key: "namelist",
          title: "名单库选择",
          desc: "选择中台管理系统的名单",
          icon: "el-icon-s-order",
          btnText: "选择名单",
          uploaded: false,
          disabled: true,
        },
      ],
      // 质量指标
      metrics: [
        {
          key: "completeness",
          title: "数据完整性",
          value: "98.5%",
          level: "success",
        },
        {
          key: "consistency",
          title: "格式一致性",
          value: "95.2%",
          level: "info",
        },
        {
          key: "continuity",
          title: "余额连续性",
          value: "92.8%",
          level: "info",
        },
      ],
      // === 批量上传相关 ===
      batchUploadDialogVisible: false,
      selectedFiles: [],
      uploadLoading: false,

      // === 统计数据 ===
      statistics: {
        uploading: 0,
        parsing: 0,
        parsed_success: 0,
        parsed_failed: 0,
      },

      // === 文件列表相关 ===
      fileUploadList: [],
      listLoading: false,
      queryParams: {
        projectId: null,
        pageNum: 1,
        pageSize: 10,
      },
      total: 0,

      // === 轮询相关 ===
      pollingTimer: null,
      pollingEnabled: false,
      pollingInterval: 5000,
    };
  },
  computed: {
    pullBankInfoDatePickerOptions() {
      return {
        disabledDate: (time) => this.isPullBankInfoDateDisabled(time),
      };
    },
  },
  created() {
    // 加载初始数据
    // this.loadInitialData();
    // 监听路由变化更新选中菜单
    this.updateActiveMenu();
  },
  mounted() {
    // 组件挂载后监听项目ID变化
    this.$watch("projectId", this.loadInitialData);

    // 加载统计数据和文件列表
    this.loadStatistics();
    this.loadFileList();

    // 检查是否需要启动轮询
    this.$nextTick(() => {
      if (this.statistics.uploading > 0 || this.statistics.parsing > 0) {
        this.startPolling();
      }
    });
  },
  beforeDestroy() {
    this.stopPolling();
  },
  methods: {
    /** 加载初始数据 */
    async loadInitialData() {
      if (!this.projectId) return;

      try {
        this.loading = true;

        // 并行加载上传状态和名单库选项
        const [uploadStatusRes, nameListRes] = await Promise.all([
          getUploadStatus(this.projectId),
          getNameListOptions(),
        ]);

        this.uploadStatusList = uploadStatusRes.data || [];
        this.nameListOptions = nameListRes.data || [];

        // 更新上传卡片状态
        this.updateUploadCards();

        // 模拟更新质量指标（实际应从API获取）
        this.updateQualityMetrics();
      } catch (error) {
        console.error("加载初始数据失败:", error);
        this.$message.error("加载数据失败");
      } finally {
        this.loading = false;
      }
    },

    /** 更新上传卡片状态 */
    updateUploadCards() {
      const statusMap = {};
      this.uploadStatusList.forEach((item) => {
        statusMap[item.uploadType] = item;
      });

      this.uploadCards.forEach((card) => {
        const status = statusMap[card.key.toUpperCase()];
        if (status) {
          card.uploaded = status.uploaded;
          card.btnText = status.uploaded
            ? "已上传" + card.title.replace("导入", "").replace("上传", "")
            : card.btnText;
        }
      });
    },

    /** 更新质量指标 */
    updateQualityMetrics() {
      // 模拟更新质量指标
      this.metrics.forEach((metric) => {
        if (metric.key === "completeness") {
          metric.value = "98.5%";
          metric.level = "success";
        } else if (metric.key === "consistency") {
          metric.value = "95.2%";
          metric.level = "info";
        } else if (metric.key === "continuity") {
          metric.value = "92.8%";
          metric.level = "info";
        }
      });
    },

    /** 菜单点击 */
    handleMenuClick(key, route) {
      const menuItem = this.menuItems.find((m) => m.key === key);
      if (menuItem) {
        this.currentMenuTitle = menuItem.label;
      }
      if (key === "upload") {
        this.activeMenu = key;
      } else {
        // 其他菜单项通知父组件跳转
        this.$emit("menu-change", { key, route });
      }
    },
    /** 更新当前选中菜单 */
    updateActiveMenu() {
      this.activeMenu = "upload";
      this.currentMenuTitle = "上传数据";
    },
    /** 上传卡片点击 */
    handleUploadClick(key) {
      const card = this.uploadCards.find((c) => c.key === key);
      if (!card || card.disabled) return;

      if (key === "transaction") {
        // 流水导入 - 打开批量上传弹窗
        this.batchUploadDialogVisible = true;
        this.selectedFiles = [];
      } else if (key === "credit") {
        // 征信导入 - 保持现有逻辑
        this.uploadFileType = key;
        this.uploadDialogTitle = `上传${card.title}`;
        this.uploadFileTypes = card.desc.replace(/.*支持|上传/g, "").trim();
        this.showUploadDialog = true;
      } else if (key === "namelist") {
        // 名单库选择 - 保持现有逻辑
        this.showNameListDialog = true;
      }
    },
    /** 文件选择变化 */
    handleFileChange(file, fileList) {
      this.fileList = fileList.slice(-1); // 只保留最后一个文件
    },
    /** 确认上传 */
    async handleConfirmUpload() {
      if (this.fileList.length === 0) {
        this.$message.warning("请选择要上传的文件");
        return;
      }
      this.uploading = true;
      try {
        // 调用上传API
        const res = await uploadFile(
          this.projectId,
          this.uploadFileType.toUpperCase(),
          this.fileList[0].raw
        );

        this.uploading = false;
        this.showUploadDialog = false;

        this.$message.success("文件上传成功，正在处理中...");
        this.$emit("data-uploaded", { type: this.uploadFileType });

        // 刷新上传状态
        await this.loadUploadStatus();

        // 开始轮询任务状态
        this.startPolling(res.data);
      } catch (error) {
        this.uploading = false;
        this.$message.error("上传失败：" + (error.msg || "未知错误"));
      } finally {
        this.fileList = [];
      }
    },

    /** 轮询任务状态 */
    startPolling(taskId) {
      const maxAttempts = 20; // 最多轮询20次（约10分钟）
      let attempts = 0;

      const poll = async () => {
        if (attempts >= maxAttempts) {
          this.$message.warning("文件处理超时，请稍后查看");
          return;
        }

        try {
          const res = await getImportStatus(taskId);
          const status = res.data;

          if (!status) {
            attempts++;
            setTimeout(poll, 30000); // 30秒后再次查询
            return;
          }

          if (status.uploadStatus === "SUCCESS") {
            // 处理完成，刷新状态
            await this.loadUploadStatus();
            this.$message.success("文件处理完成");
            return;
          } else if (status.uploadStatus === "FAILED") {
            // 处理失败
            await this.loadUploadStatus();
            this.$message.error(
              "文件处理失败：" + (status.errorMessage || "未知错误")
            );
            return;
          }

          // 继续处理中
          attempts++;
          setTimeout(poll, 30000);
        } catch (error) {
          console.error("轮询任务状态失败:", error);
          attempts++;
          setTimeout(poll, 30000);
        }
      };

      poll();
    },

    /** 加载上传状态 */
    async loadUploadStatus() {
      try {
        const res = await getUploadStatus(this.projectId);
        this.uploadStatusList = res.data || [];
        this.updateUploadCards();
      } catch (error) {
        console.error("加载上传状态失败:", error);
      }
    },
    /** 确认选择名单 */
    async handleConfirmNameList() {
      if (!this.nameListForm.type || !this.nameListForm.source) {
        this.$message.warning("请完善名单选择信息");
        return;
      }
      try {
        // 调用更新名单API
        await updateNameListSelection(this.projectId, {
          nameLists: [
            {
              type: this.nameListForm.type,
              source: this.nameListForm.source,
            },
          ],
        });

        const card = this.uploadCards.find((c) => c.key === "namelist");
        if (card) {
          card.uploaded = true;
          card.btnText = "已选择名单";
        }

        this.showNameListDialog = false;
        this.$message.success("名单选择成功");
        this.$emit("name-selected", this.nameListForm);
      } catch (error) {
        this.$message.error("名单选择失败：" + (error.msg || "未知错误"));
      }
    },
    /** 生成报告 */
    async handleGenerateReport() {
      this.$confirm("确认生成报告吗？", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(async () => {
          try {
            const loading = this.$loading({
              lock: true,
              text: "正在生成报告...",
              spinner: "el-icon-loading",
              background: "rgba(0, 0, 0, 0.7)",
            });

            // await generateReport(this.projectId);

            loading.close();
            this.$message.success("报告生成成功");
            this.$emit("generate-report");
          } catch (error) {
            this.$message.error("生成报告失败：" + (error.msg || "未知错误"));
          }
        })
        .catch(() => {});
    },
    openPullBankInfoDialog() {
      this.pullBankInfoDialogVisible = true;
    },
    resetPullBankInfoForm() {
      this.pullBankInfoForm = {
        idCardText: "",
        dateRange: [],
      };
      this.idCardFileList = [];
      this.parsingIdCardFile = false;
      this.pullBankInfoLoading = false;
    },
    parseIdCardText(text) {
      return Array.from(
        new Set(
          (text || "")
            .split(/[\n,，]+/)
            .map((item) => item.trim())
            .filter(Boolean)
        )
      );
    },
    mergeIdCards(currentText, parsedIdCards) {
      const merged = [
        ...this.parseIdCardText(currentText),
        ...((parsedIdCards || [])
          .map((item) => String(item || "").trim())
          .filter(Boolean)),
      ];
      return Array.from(new Set(merged)).join(", ");
    },
    async handleIdCardFileChange(file, fileList) {
      const latestFile = (fileList || []).slice(-1);
      const currentFile = latestFile[0] || file;
      const fileName = (currentFile && currentFile.name) || "";
      const isExcel = /\.(xls|xlsx)$/i.test(fileName);

      if (!isExcel) {
        this.idCardFileList = [];
        this.$message.error("仅支持上传 .xls 或 .xlsx 文件");
        return;
      }

      if (!currentFile || !currentFile.raw) {
        this.idCardFileList = [];
        this.$message.error("未获取到有效文件");
        return;
      }

      this.idCardFileList = latestFile;
      this.parsingIdCardFile = true;

      try {
        const res = await parseIdCardFile(currentFile.raw);
        const parsedIdCards =
          (res && res.data && Array.isArray(res.data.idCards) && res.data.idCards) ||
          [];
        this.pullBankInfoForm.idCardText = this.mergeIdCards(
          this.pullBankInfoForm.idCardText,
          parsedIdCards
        );
        this.$message.success(
          `身份证文件解析成功，共 ${parsedIdCards.length} 条有效身份证`
        );
      } catch (error) {
        this.idCardFileList = [];
        this.$message.error(
          "身份证文件解析失败：" +
            ((error && error.message) || "未知错误")
        );
      } finally {
        this.parsingIdCardFile = false;
      }
    },
    handleIdCardFileRemove() {
      this.idCardFileList = [];
      this.parsingIdCardFile = false;
    },
    getPullBankInfoTodayStart() {
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      return today;
    },
    getPullBankInfoMaxSelectableDate() {
      const yesterday = this.getPullBankInfoTodayStart();
      yesterday.setDate(yesterday.getDate() - 1);
      return yesterday;
    },
    parsePullBankInfoDate(dateValue) {
      if (!dateValue) return null;
      const [year, month, day] = String(dateValue)
        .split("-")
        .map((item) => Number(item));
      if (![year, month, day].every(Number.isFinite)) {
        return null;
      }
      return new Date(year, month - 1, day);
    },
    isPullBankInfoDateDisabled(time) {
      return time.getTime() >= this.getPullBankInfoTodayStart().getTime();
    },
    hasInvalidPullBankInfoDateRange(dateRange) {
      const maxSelectableDate = this.getPullBankInfoMaxSelectableDate();
      return (dateRange || []).some((dateValue) => {
        const date = this.parsePullBankInfoDate(dateValue);
        return !date || date.getTime() > maxSelectableDate.getTime();
      });
    },
    buildFinalIdCardList() {
      return this.parseIdCardText(this.pullBankInfoForm.idCardText);
    },
    async handleConfirmPullBankInfo() {
      const idCards = this.buildFinalIdCardList();
      const [startDate, endDate] = this.pullBankInfoForm.dateRange || [];

      if (idCards.length === 0) {
        this.$message.warning("请至少输入一个身份证号");
        return;
      }

      if (!startDate || !endDate) {
        this.$message.warning("请选择完整的时间跨度");
        return;
      }

      if (this.hasInvalidPullBankInfoDateRange([startDate, endDate])) {
        this.$message.warning("时间跨度最晚只能选择到昨天");
        return;
      }

      this.pullBankInfoLoading = true;

      try {
        const payload = {
          projectId: this.projectId,
          idCards,
          startDate,
          endDate,
        };
        const res = await pullBankInfo(payload);

        this.pullBankInfoDialogVisible = false;
        this.resetPullBankInfoForm();
        this.$message.success((res && res.msg) || "拉取任务已提交");

        await Promise.all([this.loadStatistics(), this.loadFileList()]);

        const hasPollingRecords =
          this.statistics.uploading > 0 ||
          this.statistics.parsing > 0 ||
          this.fileUploadList.some((item) =>
            ["uploading", "parsing"].includes(item.fileStatus)
          );

        if (hasPollingRecords) {
          this.startPolling();
        }
      } catch (error) {
        this.pullBankInfoLoading = false;
        this.$message.error(
          "拉取本行信息失败：" + ((error && error.message) || "未知错误")
        );
      }
    },
    /** 拉取本行信息 */
    handleFetchBankInfo() {
      this.resetPullBankInfoForm();
      this.openPullBankInfoDialog();
    },
    /** 获取进度条偏移 */
    getProgressOffset(value) {
      const percentage = parseFloat(value);
      return this.circumference * (1 - percentage / 100);
    },
    /** 获取进度条颜色 */
    getProgressColor(level) {
      const colorMap = {
        success: "#52c41a",
        info: "#1890ff",
        warning: "#fa8c16",
        danger: "#f5222d",
      };
      return colorMap[level] || "#1890ff";
    },
    /** 格式化更新时间 */
    formatUpdateTime(time) {
      if (!time) return "-";
      const date = new Date(time);
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, "0");
      const day = String(date.getDate()).padStart(2, "0");
      const hours = String(date.getHours()).padStart(2, "0");
      const minutes = String(date.getMinutes()).padStart(2, "0");
      return `${year}-${month}-${day} ${hours}:${minutes}`;
    },
    /** 获取状态样式类 */
    getStatusClass() {
      const status = String(this.projectInfo.projectStatus);
      const statusMap = {
        0: "processing",
        1: "success",
        2: "archived",
      };
      return statusMap[status] || "processing";
    },
    /** 获取状态标签 */
    getStatusLabel() {
      const status = String(this.projectInfo.projectStatus);
      const statusMap = {
        0: "进行中",
        1: "已完成",
        2: "已归档",
      };
      return statusMap[status] || "未知";
    },

    // === 批量上传相关方法 ===

    /** 批量上传的文件选择变化 */
    handleBatchFileChange(file, fileList) {
      if (fileList.length > 100) {
        this.$message.warning("最多上传100个文件");
        fileList = fileList.slice(0, 100);
      }

      const validTypes = ['.pdf', '.csv', '.xlsx', '.xls'];
      const invalidFiles = fileList.filter((f) => {
        const ext = f.name.substring(f.name.lastIndexOf(".")).toLowerCase();
        return !validTypes.includes(ext);
      });

      if (invalidFiles.length > 0) {
        this.$message.error("仅支持 PDF、CSV、Excel 格式文件");
        return;
      }

      const oversizedFiles = fileList.filter((f) => f.size > 50 * 1024 * 1024);
      if (oversizedFiles.length > 0) {
        this.$message.error("单个文件不能超过50MB");
        return;
      }

      this.selectedFiles = fileList;
    },

    /** 删除已选文件 */
    handleRemoveFile(index) {
      this.selectedFiles.splice(index, 1);
    },

    /** 开始批量上传 */
    async handleBatchUpload() {
      if (this.selectedFiles.length === 0) {
        this.$message.warning("请选择要上传的文件");
        return;
      }

      this.uploadLoading = true;

      try {
        const res = await batchUploadFiles(
          this.projectId,
          this.selectedFiles.map((f) => f.raw)
        );

        this.uploadLoading = false;
        this.batchUploadDialogVisible = false;

        this.$message.success("上传任务已提交，请查看处理进度");

        // 刷新数据并启动轮询
        await Promise.all([this.loadStatistics(), this.loadFileList()]);

        this.startPolling();
      } catch (error) {
        this.uploadLoading = false;
        this.$message.error("上传失败：" + (error.msg || "未知错误"));
      }
    },

    // === 统计和列表相关方法 ===

    /** 加载统计数据 */
    async loadStatistics() {
      try {
        const res = await getFileUploadStatistics(this.projectId);
        this.statistics = res.data || {
          uploading: 0,
          parsing: 0,
          parsed_success: 0,
          parsed_failed: 0,
        };
      } catch (error) {
        console.error("加载统计数据失败:", error);
      }
    },

    /** 加载文件列表 */
    async loadFileList() {
      this.listLoading = true;

      try {
        const params = {
          projectId: this.projectId,
          pageNum: this.queryParams.pageNum,
          pageSize: this.queryParams.pageSize,
        };

        const res = await getFileUploadList(params);
        this.fileUploadList = res.rows || [];
        this.total = res.total || 0;
      } catch (error) {
        this.$message.error("加载文件列表失败");
        console.error(error);
      } finally {
        this.listLoading = false;
      }
    },

    // === 轮询相关方法 ===

    /** 启动轮询 */
    startPolling() {
      if (this.pollingEnabled) return;
      this.pollingEnabled = true;

      const poll = () => {
        if (!this.pollingEnabled) return;

        Promise.all([this.loadStatistics(), this.loadFileList()])
          .then(() => {
            if (
              this.statistics.uploading === 0 &&
              this.statistics.parsing === 0
            ) {
              this.stopPolling();
              return;
            }
            this.pollingTimer = setTimeout(poll, this.pollingInterval);
          })
          .catch((error) => {
            console.error("轮询失败:", error);
            this.pollingTimer = setTimeout(poll, this.pollingInterval);
          });
      };

      poll();
    },

    /** 停止轮询 */
    stopPolling() {
      this.pollingEnabled = false;
      if (this.pollingTimer) {
        clearTimeout(this.pollingTimer);
        this.pollingTimer = null;
      }
    },

    /** 手动刷新 */
    async handleManualRefresh() {
      await Promise.all([this.loadStatistics(), this.loadFileList()]);

      this.$message.success("刷新成功");

      if (this.statistics.uploading > 0 || this.statistics.parsing > 0) {
        this.startPolling();
      }
    },

    // === 辅助方法 ===

    /** 分页变化 */
    handlePageChange(pageNum) {
      this.queryParams.pageNum = pageNum;
      this.loadFileList();
    },

    getRowAction(row) {
      return getUploadFileAction(row.fileStatus);
    },

    handleRowAction(row) {
      const action = this.getRowAction(row);
      if (!action) {
        return;
      }

      if (action.key === "viewError") {
        this.handleViewError(row);
        return;
      }

      if (action.key === "delete") {
        this.handleDeleteFile(row);
      }
    },

    handleViewError(row) {
      this.$alert(row.errorMessage || "未知错误", "错误信息", {
        confirmButtonText: "确定",
        type: "error",
      });
    },

    async handleDeleteFile(row) {
      try {
        await this.$confirm(
          "删除后将同步删除流水分析平台中的文件，并清除本系统中该文件对应的所有银行流水数据，是否继续？",
          "提示",
          {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          }
        );

        await deleteFileUploadRecord(row.id);
        this.$message.success("删除成功");
        await Promise.all([this.loadStatistics(), this.loadFileList()]);

        if (this.hasActivePollingRecords()) {
          this.startPolling();
        } else {
          this.stopPolling();
        }
      } catch (error) {
        if (error === "cancel" || error === "close") {
          return;
        }

        this.$message.error("删除失败：" + ((error && error.message) || "未知错误"));
      }
    },

    hasActivePollingRecords() {
      return (
        this.statistics.uploading > 0 ||
        this.statistics.parsing > 0 ||
        this.fileUploadList.some((item) =>
          ["uploading", "parsing"].includes(item.fileStatus)
        )
      );
    },

    /** 状态文本映射 */
    getStatusText(status) {
      return getUploadFileStatusText(status);
    },

    /** 状态标签类型映射 */
    getStatusType(status) {
      return getUploadFileStatusType(status);
    },

    /** 格式化文件大小 */
    formatFileSize(bytes) {
      if (bytes === 0) return "0 B";
      const k = 1024;
      const sizes = ["B", "KB", "MB", "GB"];
      const i = Math.floor(Math.log(bytes) / Math.log(k));
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    },
    /** 格式化上传时间 */
    formatUploadTime(time) {
      const formatted = parseTime(time, "{y}-{m}-{d} {h}:{i}:{s}");
      return formatted || "-";
    },
  },
};
</script>

<style lang="scss" scoped>
.upload-data-container {
  padding: 16px;
  background: #fff;
  min-height: 100%;
}

// 侧边栏
.sidebar {
  background: #ffffff;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  padding: 16px;
  height: 100%;
  display: flex;
  flex-direction: column;

  .sidebar-header {
    font-size: 16px;
    font-weight: 600;
    color: #303133;
    margin-bottom: 20px;
    padding-bottom: 12px;
    border-bottom: 1px solid #ebeef5;
  }

  .sidebar-menu {
    list-style: none;
    padding: 0;
    margin: 0 0 auto 0;
    flex: 1;

    .menu-item {
      display: flex;
      align-items: center;
      padding: 10px 12px;
      margin-bottom: 4px;
      cursor: pointer;
      border-radius: 4px;
      font-size: 14px;
      color: #606266;
      transition: all 0.3s;
      position: relative;

      &:hover {
        background: #f5f7fa;
        color: #303133;
      }

      &.active {
        background: #1890ff;
        color: #ffffff;

        .menu-dot {
          display: block;
        }
      }

      .menu-dot {
        display: none;
        width: 4px;
        height: 4px;
        background: #ffffff;
        border-radius: 50%;
        margin-right: 8px;
      }
    }
  }

  .sidebar-footer {
    border-top: 1px solid #ebeef5;
    padding-top: 16px;
    margin-top: 16px;

    .status {
      font-size: 13px;
      color: #606266;
      margin-bottom: 8px;

      .status-processing {
        color: #1890ff;
        font-weight: 500;
      }

      .status-success {
        color: #52c41a;
        font-weight: 500;
      }

      .status-archived {
        color: #909399;
        font-weight: 500;
      }
    }

    .update-time {
      font-size: 12px;
      color: #909399;
    }
  }
}

// 主内容区
.main-content {
  .content-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;

    .content-title {
      margin: 0;
      font-size: 18px;
      font-weight: 600;
      color: #303133;
    }

    .header-actions {
      display: flex;
      gap: 12px;
    }
  }

  // 上传模块
  .upload-section {
    background: #ffffff;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    padding: 20px;
    margin-bottom: 16px;

    .upload-cards {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 16px;

      .upload-card {
        border: 1px solid #ebeef5;
        border-radius: 4px;
        padding: 20px 16px;
        text-align: center;
        transition: all 0.3s;
        background-color: #fff;

        &:hover {
          border-color: #1890ff;
          box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
        }

        &.is-disabled {
          background-color: #fafafa;
          border-color: #ebeef5;
          opacity: 0.7;

          &:hover {
            border-color: #ebeef5;
            box-shadow: none;
          }

          .card-icon,
          .card-title,
          .card-desc {
            color: #c0c4cc;
          }
        }

        .card-icon {
          font-size: 32px;
          color: #1890ff;
          margin-bottom: 12px;

          i {
            font-size: 32px;
          }
        }

        .card-title {
          font-size: 16px;
          font-weight: 500;
          color: #303133;
          margin-bottom: 8px;
        }

        .card-desc {
          font-size: 13px;
          color: #909399;
          margin-bottom: 16px;
          min-height: 36px;
          line-height: 1.4;
        }

        .el-upload {
          width: 100%;
        }
      }
    }
  }

  // 数据质量检查
  .quality-check-section {
    background: #ffffff;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    padding: 20px;

    .section-header {
      display: flex;
      align-items: center;
      margin-bottom: 20px;

      .warning-icon {
        font-size: 18px;
        color: #fa8c16;
        margin-right: 8px;
      }

      span {
        font-size: 15px;
        font-weight: 500;
        color: #303133;
      }
    }

    .metrics {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 32px;

      .metric-card {
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: 16px;
        border: 1px solid #ebeef5;
        border-radius: 4px;
        background: #fafafa;

        .metric-title {
          font-size: 14px;
          color: #606266;
          margin-bottom: 12px;
        }

        .metric-value {
          font-size: 24px;
          font-weight: 600;
          margin-bottom: 12px;

          &.value-success {
            color: #52c41a;
          }

          &.value-info {
            color: #1890ff;
          }

          &.value-warning {
            color: #fa8c16;
          }

          &.value-danger {
            color: #f5222d;
          }
        }

        .progress-ring-container {
          width: 48px;
          height: 48px;

          .progress-ring {
            width: 48px;
            height: 48px;
            transform: rotate(-90deg);

            .progress-ring-bg {
              stroke: #ebeef5;
            }

            .progress-ring-progress {
              transition: stroke-dashoffset 0.5s ease;
            }
          }
        }
      }
    }
  }
}

// 文件列表区域
.file-list-section {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);

  .list-toolbar {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    margin-bottom: 16px;
  }
}

// 上传弹窗样式
::v-deep .el-dialog__wrapper {
  .upload-area,
  .batch-upload-area {
    width: 100%;
  }

  .upload-area .el-upload,
  .batch-upload-area .el-upload {
    width: 100%;
  }

  .upload-area .el-upload-dragger,
  .batch-upload-area .el-upload-dragger {
    width: 100%;
    height: 200px;
  }

  .el-upload__tip {
    margin-top: 8px;
    color: #909399;
    font-size: 12px;
  }
}

.pull-bank-info-form {
  .pull-bank-field-tip {
    margin-top: 8px;
    font-size: 12px;
    color: #909399;
    line-height: 1.5;
  }
}

.pull-bank-file-panel {
  padding: 16px;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  background: #fafcff;

  .pull-bank-file-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
  }

  .pull-bank-file-tip {
    font-size: 12px;
    color: #606266;
    line-height: 1.5;
  }
}

.pull-bank-file-upload {
  display: inline-flex;
  flex: 0 0 auto;
}

.selected-id-card-file {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 6px;
  background: #ffffff;
  border: 1px solid #ebeef5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;

  .selected-id-card-file__info {
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    color: #303133;
  }

  .selected-id-card-file__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .el-button {
    flex-shrink: 0;
    padding: 0;
  }
}

.pull-bank-range-picker {
  width: 100%;
}

// 批量上传弹窗样式
.batch-upload-area {
  width: 100%;

  ::v-deep .el-upload {
    width: 100%;

    .el-upload-dragger {
      width: 100%;
      height: 180px;
    }
  }
}

.selected-files {
  margin-top: 16px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  max-height: 300px;
  overflow-y: auto;

  .files-header {
    padding: 12px 16px;
    background: #f5f7fa;
    border-bottom: 1px solid #ebeef5;
    font-size: 14px;
    font-weight: 500;
    color: #606266;
  }

  .files-list {
    padding: 8px;

    .file-item {
      display: flex;
      align-items: center;
      padding: 8px 12px;
      border-radius: 4px;
      transition: background 0.3s;

      &:hover {
        background: #f5f7fa;
      }

      i {
        font-size: 18px;
        color: #1890ff;
        margin-right: 8px;
      }

      .file-name {
        flex: 1;
        font-size: 14px;
        color: #303133;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .file-size {
        font-size: 12px;
        color: #909399;
        margin: 0 12px;
      }

      .el-button {
        padding: 4px;
        color: #909399;

        &:hover {
          color: #f56c6c;
        }
      }
    }
  }
}

.parse-tip {
  margin-top: 8px;
  font-size: 12px;
  color: #909399;
}

// 响应式
@media (max-width: 1200px) {
  .upload-section .upload-cards {
    grid-template-columns: repeat(2, 1fr);
  }

  .quality-check-section .metrics {
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
  }

}

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

  .sidebar {
    margin-bottom: 16px;
  }

  .content-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .upload-section .upload-cards {
    grid-template-columns: 1fr;
  }

  .quality-check-section .metrics {
    grid-template-columns: 1fr;
  }

  .file-list-section .list-toolbar {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .pull-bank-file-panel {
    padding: 12px;

    .pull-bank-file-actions {
      align-items: stretch;
      gap: 10px;
    }
  }

  .pull-bank-file-upload {
    width: 100%;
  }

  .selected-id-card-file {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>
