import { bitable, FieldType } from '@lark-base-open/js-sdk';
import { Button, Typography, List, Card, Space, Divider, Spin, Table, Select, Modal, DatePicker, InputNumber } from '@douyinfe/semi-ui';
import { useState, useEffect } from 'react';
import { addDays, format } from 'date-fns';
import { zhCN } from 'date-fns/locale';
import { executePricingQuery, executeSecondaryProcessQuery, executePricingDetailsQuery } from './services/apiService';

const { Title, Text } = Typography;

// 统一的日期格式常量
const DATE_FORMATS = {import { bitable, FieldType } from '@lark-base-open/js-sdk';
import { Button, Typography, List, Card, Space, Divider, Spin, Table, Select, Modal, DatePicker, InputNumber } from '@douyinfe/semi-ui';
import { useState, useEffect } from 'react';
import { addDays, format } from 'date-fns';
import { zhCN } from 'date-fns/locale';
import { executePricingQuery, executeSecondaryProcessQuery, executePricingDetailsQuery } from './services/apiService';

const { Title, Text } = Typography;

// 统一的日期格式常量
const DATE_FORMATS = {
  DISPLAY_WITH_TIME: 'yyyy-MM-dd HH:mm',           // 显示格式：2026-02-20 16:54
  DISPLAY_DATE_ONLY: 'yyyy-MM-dd',                 // 日期格式：2026-02-20
  STORAGE_FORMAT: 'yyyy-MM-dd HH:mm:ss',           // 存储格式：2026-02-20 16:54:00
  CHINESE_DATE: 'yyyy年MM月dd日',                   // 中文格式：2026年02月20日
} as const;

// 统一的星期显示
const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] as const;

// 统一的字段提取函数
const extractText = (val: any) => {
  if (Array.isArray(val) && val.length > 0) {
    const item = val[0];
    return typeof item === 'string' ? item : (item?.text || item?.name || '');
  } else if (typeof val === 'string') {
    return val;
  } else if (val && typeof val === 'object') {
    return val.text || val.name || '';
  }
  return '';
};

export default function App() {
  const [selectedRecords, setSelectedRecords] = useState<string[]>([]);
  const [recordDetails, setRecordDetails] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [queryResults, setQueryResults] = useState<any[]>([]);
  const [queryLoading, setQueryLoading] = useState(false);
  const [secondaryProcessResults, setSecondaryProcessResults] = useState<any[]>([]);
  const [secondaryProcessLoading, setSecondaryProcessLoading] = useState(false);
  const [pricingDetailsResults, setPricingDetailsResults] = useState<any[]>([]);
  const [pricingDetailsLoading, setPricingDetailsLoading] = useState(false);
  
  // 标签相关状态
  const [labelOptions, setLabelOptions] = useState<{[key: string]: any[]}>({});
  const [selectedLabels, setSelectedLabels] = useState<{[key: string]: string | string[]}>({});
  const [labelLoading, setLabelLoading] = useState(false);
  
  // 客户期望日期状态
  const [expectedDate, setExpectedDate] = useState<Date | null>(null);
  // 起始时间状态（从货期记录表获取，新记录则使用当前时间）
  const [startTime, setStartTime] = useState<Date | null>(null);
  
  // 预览相关状态（已移除未使用的 previewLoading 状态）
  
  // 时效计算相关状态
  const [timelineVisible, setTimelineVisible] = useState(false);
  const [timelineLoading, setTimelineLoading] = useState(false);
  const [timelineResults, setTimelineResults] = useState<any[]>([]);
  const [timelineAdjustments, setTimelineAdjustments] = useState<{[key: number]: number}>({});
  // 交期余量扣减状态：记录从交期余量中扣减的天数
  const [deliveryMarginDeductions, setDeliveryMarginDeductions] = useState<number>(0);
  // 最后流程完成日期调整状态：记录最后流程完成日期增加的天数
  const [completionDateAdjustment, setCompletionDateAdjustment] = useState<number>(0);
  // 实际完成日期状态：记录每个节点的实际完成日期
  const [actualCompletionDates, setActualCompletionDates] = useState<{[key: number]: Date | null}>({});
  // 基础缓冲期天数（可配置），用于计算动态缓冲期，默认14天
  const [baseBufferDays, setBaseBufferDays] = useState<number>(14);
  // 快照回填来源（foreign_id、款式、颜色、文本2）
  const [currentForeignId, setCurrentForeignId] = useState<string | null>(null);
  const [currentStyleText, setCurrentStyleText] = useState<string>('');
  const [currentColorText, setCurrentColorText] = useState<string>('');
  const [currentText2, setCurrentText2] = useState<string>('');
  const [currentVersionNumber, setCurrentVersionNumber] = useState<number | null>(null);
  // 功能入口模式与调整相关状态
  const [mode, setMode] = useState<'generate' | 'adjust' | null>(null);
  const [modeSelectionVisible, setModeSelectionVisible] = useState(true);
  const [adjustLoading, setAdjustLoading] = useState(false);
  // 删除未使用的 deliveryRecords 状态
  const [selectedDeliveryRecordId, setSelectedDeliveryRecordId] = useState<string>('');
  
  // 批量处理相关状态
  const [batchProcessing, setBatchProcessing] = useState(false);
  const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0 });
  const [batchRowCount, setBatchRowCount] = useState<number>(10); // 默认处理10行
  
  // 批量处理当前记录信息（用于保存时传递正确的数据）
  const [currentBatchRecord, setCurrentBatchRecord] = useState<{
    selectedRecords: string[],
    recordDetails: any[],
    labels: Record<string, any>,
    expectedDate: any,
    startTime: any
  } | null>(null);
  
  // 批量处理表和视图选择状态
  const [selectedBatchTableId, setSelectedBatchTableId] = useState<string>('');
  const [selectedBatchViewId, setSelectedBatchViewId] = useState<string>('');
  const [availableTables, setAvailableTables] = useState<Array<{id: string, name: string}>>([]);
  const [availableViews, setAvailableViews] = useState<Array<{id: string, name: string}>>([]);
  const [tablesLoading, setTablesLoading] = useState(false);
  const [viewsLoading, setViewsLoading] = useState(false);
  
  // 全局变量重置：在切换功能或切换版单/批量数据时，清空页面与计算相关状态
  const resetGlobalState = (opts?: { resetMode?: boolean }) => {
    // 运行时加载状态
    setLoading(false);
    setQueryLoading(false);
    setSecondaryProcessLoading(false);
    setPricingDetailsLoading(false);
    setLabelLoading(false);
    setAdjustLoading(false);
    setTimelineLoading(false);
    setBatchProcessing(false);
    setBatchProgress({ current: 0, total: 0 });

    // 页面与计算数据
    setSelectedRecords([]);
    setRecordDetails([]);
    setSelectedLabels({});
    setExpectedDate(null);
    setStartTime(null);
    setTimelineVisible(false);
    setTimelineResults([]);
    setTimelineAdjustments({});
    setIsRestoringSnapshot(false);

    // 当前记录与批量信息
    setCurrentBatchRecord(null);

    // 当前回填状态
    setCurrentForeignId(null);
    setCurrentStyleText('');
    setCurrentColorText('');
    setCurrentText2('');
    setCurrentVersionNumber(null);

    // 可选：重置模式
    if (opts?.resetMode) {
      setMode(null);
      setModeSelectionVisible(true);
    }
  };

  // 指定的数据表ID和视图ID
  const TABLE_ID = 'tblPIJ7unndydSMu';
  const VIEW_ID = 'vewb28sjuX';

  // 标签表ID
  const LABEL_TABLE_ID = 'tblPnQscqwqopJ8V';

  // 流程配置表ID
  const PROCESS_CONFIG_TABLE_ID = 'tblMygOc6T9o4sYU';
  const NODE_NAME_FIELD_ID = 'fld0g9L9Fw'; // 节点名称字段
  const PROCESS_LABEL_FIELD_ID = 'fldrVTa23X'; // 流程配置表的标签字段
  const PROCESS_ORDER_FIELD_ID = 'fldbfJQ4Zs'; // 流程顺序字段ID
  const WEEKEND_DAYS_FIELD_ID = 'fld2BvjbIN'; // 休息日字段ID（多选项：0-6代表周一到周日）
  const START_DATE_RULE_FIELD_ID = 'fld0KsQ2j3'; // 起始日期调整规则字段ID
  const DATE_ADJUSTMENT_RULE_FIELD_ID = 'fld0KsQ2j3'; // 日期调整规则字段ID
  const EXCLUDED_DATES_FIELD_ID = 'fldGxzC5uG'; // 不参与计算日期（多选，格式：yyyy-MM-dd）
  
  // 时效数据表相关常量
  const TIMELINE_TABLE_ID = 'tblPnQscqwqopJ8V'; // 时效数据表ID
  const TIMELINE_FIELD_ID = 'fldniJmZe3'; // 时效值字段ID
  const TIMELINE_NODE_FIELD_ID = 'fldeIZzokl'; // 时效表中的节点名称字段ID
  const CALCULATION_METHOD_FIELD_ID = 'fldxfLZNUu'; // 时效计算方式字段ID

  // 新表ID（批量生成表）
  const BATCH_TABLE_ID = 'tbl673YuipMIJnXL'; // 新创建的多维表格ID

  // 已移除：调整模式不再加载货期记录列表

  // 入口选择处理
  const chooseMode = (m: 'generate' | 'adjust') => {
    // 切换功能时重置全局变量，但保留新的mode
    resetGlobalState({ resetMode: false });
    setMode(m);
    setModeSelectionVisible(false);
  };

  // 根据货期记录ID读取节点详情并还原流程数据
  const loadProcessDataFromDeliveryRecord = async (deliveryRecordId: string) => {
    if (!deliveryRecordId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'warning', message: '请先选择一条货期记录' });
      }
      return;
    }
    setTimelineLoading(true);
    try {
      const deliveryTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
      const deliveryRecord = await deliveryTable.getRecordById(deliveryRecordId);
      const nodeDetailsVal = deliveryRecord?.fields?.[DELIVERY_NODE_DETAILS_FIELD_ID];

      // 优先使用货期记录表中的快照字段进行一键还原（新方案）
      try {
        const deliverySnapVal = deliveryRecord?.fields?.[DELIVERY_SNAPSHOT_JSON_FIELD_ID];
        let deliverySnapStr: string | null = null;
        if (typeof deliverySnapVal === 'string') {
          deliverySnapStr = deliverySnapVal;
        } else if (Array.isArray(deliverySnapVal)) {
          const texts = deliverySnapVal
            .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
            .map((el: any) => el.text);
          deliverySnapStr = texts.length > 0 ? texts.join('') : null;
        } else if (deliverySnapVal && typeof deliverySnapVal === 'object') {
          if ((deliverySnapVal as any).text && typeof (deliverySnapVal as any).text === 'string') {
            deliverySnapStr = (deliverySnapVal as any).text;
          } else if ((deliverySnapVal as any).type === 'text' && typeof (deliverySnapVal as any).text === 'string') {
            deliverySnapStr = (deliverySnapVal as any).text;
          }
        }

        if (deliverySnapStr && deliverySnapStr.trim() !== '') {
          setIsRestoringSnapshot(true);
          const snapshot = JSON.parse(deliverySnapStr);

          // 恢复页面与全局状态
          if (snapshot.selectedLabels) setSelectedLabels(snapshot.selectedLabels);
          if (!mode && snapshot.mode) setMode(snapshot.mode);
          if (snapshot.foreignId) setCurrentForeignId(snapshot.foreignId);
          if (snapshot.styleText) setCurrentStyleText(snapshot.styleText);
          if (snapshot.colorText) setCurrentColorText(snapshot.colorText);
          if (snapshot.text2) setCurrentText2(snapshot.text2);

          if (snapshot.generationModeState) {
            const genState = snapshot.generationModeState;
            if (genState.currentForeignId) setCurrentForeignId(genState.currentForeignId);
            if (genState.currentStyleText) setCurrentStyleText(genState.currentStyleText);
            if (genState.currentColorText) setCurrentColorText(genState.currentColorText);
            if (genState.currentText2) setCurrentText2(genState.currentText2);
            if (genState.currentVersionNumber !== undefined) setCurrentVersionNumber(genState.currentVersionNumber);
            if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
              setRecordDetails(genState.recordDetails);
            }
          }

          if (snapshot.version !== undefined) {
            let vNum: number | null = null;
            if (typeof snapshot.version === 'number') {
              vNum = snapshot.version;
            } else if (typeof snapshot.version === 'string') {
              const match = snapshot.version.match(/\d+/);
              if (match) vNum = parseInt(match[0], 10);
            }
            if (vNum !== null && !isNaN(vNum)) setCurrentVersionNumber(vNum);
          }

          if (snapshot.timelineAdjustments) setTimelineAdjustments(snapshot.timelineAdjustments);
          if (snapshot.expectedDateTimestamp) {
            setExpectedDate(new Date(snapshot.expectedDateTimestamp));
          } else if (snapshot.expectedDateString) {
            setExpectedDate(new Date(snapshot.expectedDateString));
          }

          // 优先从快照恢复起始时间
          let startTimeRestored = false;
          if (snapshot.startTimestamp) {
            setStartTime(new Date(snapshot.startTimestamp));
            startTimeRestored = true;
          } else if (snapshot.startString) {
            const parsed = new Date(snapshot.startString);
            if (!isNaN(parsed.getTime())) {
              setStartTime(parsed);
              startTimeRestored = true;
            }
          }

          if (!startTimeRestored) {
            const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
            if (startTimeValue) {
              let extractedStartTime: Date | null = null;
              if (typeof startTimeValue === 'number') {
                extractedStartTime = new Date(startTimeValue);
              } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
                const timestamp = startTimeValue[0];
                if (typeof timestamp === 'number') extractedStartTime = new Date(timestamp);
              }
              if (extractedStartTime && !isNaN(extractedStartTime.getTime())) setStartTime(extractedStartTime);
            }
          }

          // 完整快照直接包含timelineResults，优先使用
          if (Array.isArray(snapshot.timelineResults)) {
            setTimelineResults(snapshot.timelineResults);
            setTimelineVisible(true);
            if (bitable.ui.showToast) {
              await bitable.ui.showToast({ toastType: 'success', message: '已按货期记录快照还原流程数据' });
            }
            setTimelineLoading(false);
            setIsRestoringSnapshot(false);
            return;
          }

          // 兼容完整快照标识但没有直接timelineResults的情况
          if (snapshot.isCompleteSnapshot || snapshot.snapshotType === 'complete' || snapshot.isGlobalSnapshot) {
            // 若没有timelineResults，视为旧格式，保持兼容：不在此分支拼装，后续走旧流程
          } else {
            // 非完整快照则进入旧流程（从节点记录扫描快照）
          }
        }
      } catch (e) {
        console.warn('从货期记录快照字段还原失败，回退到旧流程:', e);
      }

      let recordIds: string[] = [];
      if (nodeDetailsVal && typeof nodeDetailsVal === 'object' && (nodeDetailsVal as any).recordIds) {
        recordIds = (nodeDetailsVal as any).recordIds as string[];
      } else if (Array.isArray(nodeDetailsVal)) {
        recordIds = nodeDetailsVal.map((item: any) => item?.recordId || item?.id || item).filter(Boolean);
      }

      if (!recordIds || recordIds.length === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({ toastType: 'warning', message: '该货期记录未包含节点详情或为空' });
        }
        setTimelineLoading(false);
        return;
      }

      const processTable = await bitable.base.getTable(PROCESS_DATA_TABLE_ID);
      const records = await Promise.all(recordIds.map(id => processTable.getRecordById(id)));

      // 优先使用文本2快照一模一样还原
      try {
        // 在所有记录中查找非空快照
        let snapStr: string | null = null;
        for (const rec of records) {
          const snapVal = rec?.fields?.[PROCESS_SNAPSHOT_JSON_FIELD_ID];
          let candidate: string | null = null;
          if (typeof snapVal === 'string') {
            candidate = snapVal;
          } else if (Array.isArray(snapVal)) {
            // 文本结构：拼接所有text片段
            const texts = snapVal
              .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
              .map((el: any) => el.text);
            candidate = texts.length > 0 ? texts.join('') : null;
          } else if (snapVal && typeof snapVal === 'object') {
            // 兼容 {text: '...'} 或 {type:'text', text:'...'}
            if ((snapVal as any).text && typeof (snapVal as any).text === 'string') {
              candidate = (snapVal as any).text;
            } else if ((snapVal as any).type === 'text' && typeof (snapVal as any).text === 'string') {
              candidate = (snapVal as any).text;
            }
          }
          if (candidate && candidate.trim() !== '') {
            snapStr = candidate;
            break;
          }
        }
        if (snapStr && snapStr.trim() !== '') {
          setIsRestoringSnapshot(true); // 开始快照还原
          const snapshot = JSON.parse(snapStr);
          // 恢复页面状态
          if (snapshot.selectedLabels) setSelectedLabels(snapshot.selectedLabels);
          // 保留当前模式，不覆写为快照的模式（避免调整模式被还原为生成模式）
          if (!mode && snapshot.mode) setMode(snapshot.mode);
          // 快照回填的foreign_id/款式/颜色/版本
          if (snapshot.foreignId) setCurrentForeignId(snapshot.foreignId);
          if (snapshot.styleText) setCurrentStyleText(snapshot.styleText);
          if (snapshot.colorText) setCurrentColorText(snapshot.colorText);
          if (snapshot.text2) setCurrentText2(snapshot.text2);
          
          // 恢复生成模式完整状态（如果存在）
          if (snapshot.generationModeState) {
            const genState = snapshot.generationModeState;
            if (genState.currentForeignId) setCurrentForeignId(genState.currentForeignId);
            if (genState.currentStyleText) setCurrentStyleText(genState.currentStyleText);
            if (genState.currentColorText) setCurrentColorText(genState.currentColorText);
            if (genState.currentText2) setCurrentText2(genState.currentText2);
            if (genState.currentVersionNumber !== undefined) setCurrentVersionNumber(genState.currentVersionNumber);
            if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
              // 恢复记录详情（如果需要的话）
              console.log('恢复生成模式记录详情:', genState.recordDetails.length, '条记录');
            }
            console.log('恢复生成模式状态:', {
              hasSelectedLabels: genState.hasSelectedLabels,
              labelSelectionComplete: genState.labelSelectionComplete,
              recordCount: genState.recordDetails?.length || 0
            });
          }
          
          if (snapshot.version !== undefined) {
            let vNum: number | null = null;
            if (typeof snapshot.version === 'number') {
              vNum = snapshot.version;
            } else if (typeof snapshot.version === 'string') {
              const match = snapshot.version.match(/\d+/);
              if (match) {
                vNum = parseInt(match[0], 10);
              }
            }
            if (vNum !== null && !isNaN(vNum)) setCurrentVersionNumber(vNum);
          }
          if (snapshot.timelineAdjustments) setTimelineAdjustments(snapshot.timelineAdjustments);
          if (snapshot.expectedDateTimestamp) {
            setExpectedDate(new Date(snapshot.expectedDateTimestamp));
          } else if (snapshot.expectedDateString) {
            setExpectedDate(new Date(snapshot.expectedDateString));
          }
          
          // 优先从快照恢复起始时间，如果快照中没有则从当前货期记录中获取
          let startTimeRestored = false;
          if (snapshot.startTimestamp) {
            setStartTime(new Date(snapshot.startTimestamp));
            startTimeRestored = true;
          } else if (snapshot.startString) {
            const parsed = new Date(snapshot.startString);
            if (!isNaN(parsed.getTime())) {
              setStartTime(parsed);
              startTimeRestored = true;
            }
          }
          
          // 如果快照中没有起始时间信息，则从当前选中的货期记录中获取
          if (!startTimeRestored) {
            const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
            if (startTimeValue) {
              let extractedStartTime: Date | null = null;
              if (typeof startTimeValue === 'number') {
                extractedStartTime = new Date(startTimeValue);
              } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
                const timestamp = startTimeValue[0];
                if (typeof timestamp === 'number') {
                  extractedStartTime = new Date(timestamp);
                }
              }
              
              if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
                setStartTime(extractedStartTime);
              }
            }
          }
          
          if (Array.isArray(snapshot.timelineResults)) {
            // 兼容旧版本的完整快照格式
            setTimelineResults(snapshot.timelineResults);
            setTimelineVisible(true);
            if (bitable.ui.showToast) {
              await bitable.ui.showToast({ toastType: 'success', message: '已按快照一模一样还原流程数据' });
            }
            setTimelineLoading(false);
            setIsRestoringSnapshot(false); // 快照还原完成
            return; // 快照还原完成，退出函数
          } else if (snapshot.isCompleteSnapshot || snapshot.snapshotType === 'complete' || 
                     snapshot.isGlobalSnapshot || snapshot.isCombinedSnapshot) {
            // 处理完整快照格式：每个节点都包含完整数据
            console.log('检测到完整快照格式，直接使用快照数据');
            
            // 如果是完整快照，直接使用其中的timelineResults
            if (snapshot.isCompleteSnapshot && snapshot.timelineResults) {
              console.log('使用完整快照中的timelineResults数据');
              setTimelineResults(snapshot.timelineResults);
              setTimelineVisible(true);
              
              // 恢复智能缓冲期状态
              if (snapshot.bufferManagement) {
                console.log('恢复智能缓冲期状态:', snapshot.bufferManagement);
              }
              
              // 恢复连锁调整系统状态
              if (snapshot.chainAdjustmentSystem) {
                console.log('恢复连锁调整系统状态:', snapshot.chainAdjustmentSystem);
              }
              
              // 恢复生成模式状态
              if (snapshot.generationModeState) {
                console.log('恢复生成模式状态:', snapshot.generationModeState);
                const genState = snapshot.generationModeState;
                
                // 恢复foreign_id状态
                if (genState.currentForeignId) {
                  setCurrentForeignId(genState.currentForeignId);
                  console.log('恢复foreign_id状态:', genState.currentForeignId);
                }
                
                // 恢复款式和颜色状态
                if (genState.currentStyleText) {
                  setCurrentStyleText(genState.currentStyleText);
                  console.log('恢复款式状态:', genState.currentStyleText);
                }
                if (genState.currentColorText) {
                  setCurrentColorText(genState.currentColorText);
                  console.log('恢复颜色状态:', genState.currentColorText);
                }
                
                // 恢复text2状态
                if (genState.currentText2) {
                  setCurrentText2(genState.currentText2);
                  console.log('恢复text2状态:', genState.currentText2);
                }
                
                // 恢复版本号状态
                if (genState.currentVersionNumber !== undefined) {
                  setCurrentVersionNumber(genState.currentVersionNumber);
                  console.log('恢复版本号状态:', genState.currentVersionNumber);
                }
                
                // 恢复记录详情状态
                if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
                  setRecordDetails(genState.recordDetails);
                  console.log('恢复记录详情状态，记录数量:', genState.recordDetails.length);
                }
              }
              
              // 恢复时间线计算状态
              if (snapshot.timelineCalculationState) {
                console.log('恢复时间线计算状态:', snapshot.timelineCalculationState);
              }
              
              if (bitable.ui.showToast) {
                await bitable.ui.showToast({ 
                  toastType: 'success', 
                  message: '已按完整快照还原流程数据' 
                });
              }
              setTimelineLoading(false);
              setIsRestoringSnapshot(false);
              return;
            }
            
            // 兼容旧版本分散快照格式的处理逻辑
            // 新版本的分散快照格式：需要从所有节点收集数据
            console.log('检测到新版本快照格式，开始收集所有节点的快照数据');
            
            try {
              // 收集所有节点的快照数据
              const nodeSnapshots: any[] = [];
              let globalSnapshotData = snapshot.isCompleteSnapshot ? snapshot : null;
              
              // 遍历所有记录，收集快照数据
              for (const record of records) {
                const fields = record?.fields || {};
                const snapshotField = fields[PROCESS_SNAPSHOT_JSON_FIELD_ID];
                
                if (snapshotField) {
                  let nodeSnapStr = '';
                  
                  // 解析快照字段（支持多种格式）
                  if (typeof snapshotField === 'string') {
                    nodeSnapStr = snapshotField;
                  } else if (Array.isArray(snapshotField)) {
                    const texts = snapshotField
                      .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
                      .map((el: any) => el.text);
                    nodeSnapStr = texts.length > 0 ? texts.join('') : '';
                  } else if (snapshotField && typeof snapshotField === 'object') {
                    if ((snapshotField as any).text && typeof (snapshotField as any).text === 'string') {
                      nodeSnapStr = (snapshotField as any).text;
                    }
                  }
                  
                  if (nodeSnapStr && nodeSnapStr.trim() !== '') {
                    try {
                      const nodeSnapshot = JSON.parse(nodeSnapStr);
                      
                      // 批量模式现在使用扁平化结构，直接从快照中提取全局数据
                      if (nodeSnapshot.isCompleteSnapshot && !globalSnapshotData) {
                        globalSnapshotData = {
                          version: nodeSnapshot.version,
                          foreignId: nodeSnapshot.foreignId,
                          styleText: nodeSnapshot.styleText,
                          colorText: nodeSnapshot.colorText,
                          text2: nodeSnapshot.text2,
                          mode: nodeSnapshot.mode,
                          selectedLabels: nodeSnapshot.selectedLabels,
                          expectedDateTimestamp: nodeSnapshot.expectedDateTimestamp,
                          expectedDateString: nodeSnapshot.expectedDateString,
                          startTimestamp: nodeSnapshot.startTimestamp,
                          startString: nodeSnapshot.startString,
                          timelineAdjustments: nodeSnapshot.timelineAdjustments,
                          // 恢复智能缓冲期管理状态
                          bufferManagement: nodeSnapshot.bufferManagement,
                          // 恢复连锁调整系统状态
                          chainAdjustmentSystem: nodeSnapshot.chainAdjustmentSystem,
                          // 恢复生成模式状态
                          generationModeState: nodeSnapshot.generationModeState,
                          // 恢复时间线计算状态
                          timelineCalculationState: nodeSnapshot.timelineCalculationState,
                          totalNodes: nodeSnapshot.totalNodes
                        };
                      }
                      
                      // 扁平化结构中，每个快照都包含完整的节点数据
                      if (nodeSnapshot.isCompleteSnapshot) {
                        // 确保adjustedTimelineValue有正确的默认值
                        const adjustedTimelineValue = nodeSnapshot.adjustedTimelineValue !== undefined ? 
                          nodeSnapshot.adjustedTimelineValue : nodeSnapshot.timelineValue;
                        
                        // 处理日期格式，优先使用时间戳格式
                        let estimatedStart = nodeSnapshot.estimatedStart;
                        let estimatedEnd = nodeSnapshot.estimatedEnd;
                        
                        // 如果有时间戳格式的日期，使用时间戳重新格式化
                        if (nodeSnapshot.estimatedStartTimestamp) {
                          try {
                            estimatedStart = formatDate(new Date(nodeSnapshot.estimatedStartTimestamp));
                          } catch (error) {
                            console.warn('时间戳格式开始时间转换失败:', error);
                          }
                        }
                        
                        if (nodeSnapshot.estimatedEndTimestamp) {
                          try {
                            estimatedEnd = formatDate(new Date(nodeSnapshot.estimatedEndTimestamp));
                          } catch (error) {
                            console.warn('时间戳格式结束时间转换失败:', error);
                          }
                        }
                        
                        // 调试日志
                        console.log(`节点 ${nodeSnapshot.nodeName} 快照还原:`, {
                          timelineValue: nodeSnapshot.timelineValue,
                          adjustedTimelineValue: adjustedTimelineValue,
                          originalAdjustedTimelineValue: nodeSnapshot.adjustedTimelineValue,
                          estimatedStart: estimatedStart,
                          estimatedEnd: estimatedEnd,
                          hasTimestamps: {
                            start: Boolean(nodeSnapshot.estimatedStartTimestamp),
                            end: Boolean(nodeSnapshot.estimatedEndTimestamp)
                          },
                          nodeCalculationState: nodeSnapshot.nodeCalculationState
                        });
                        
                        nodeSnapshots.push({
                          processOrder: nodeSnapshot.processOrder,
                          nodeName: nodeSnapshot.nodeName || nodeSnapshot.currentNodeName,
                          matchedLabels: nodeSnapshot.matchedLabels,
                          timelineValue: nodeSnapshot.timelineValue,
                          estimatedStart: estimatedStart,
                          estimatedEnd: estimatedEnd,
                          timelineRecordId: nodeSnapshot.timelineRecordId,
                          allMatchedRecords: nodeSnapshot.allMatchedRecords,
                          isAccumulated: nodeSnapshot.isAccumulated,
                          weekendDaysConfig: nodeSnapshot.weekendDaysConfig,
                          excludedDates: nodeSnapshot.excludedDates,
                          actualExcludedDates: nodeSnapshot.actualExcludedDates,
                          actualExcludedDatesCount: nodeSnapshot.actualExcludedDatesCount,
                          calculationMethod: nodeSnapshot.calculationMethod,
                          ruleDescription: nodeSnapshot.ruleDescription,
                          skippedWeekends: nodeSnapshot.skippedWeekends,
                          actualDays: nodeSnapshot.actualDays,
                          adjustedTimelineValue: adjustedTimelineValue,
                          adjustment: nodeSnapshot.adjustment || 0,
                          adjustmentDescription: nodeSnapshot.adjustmentDescription || '',
                          startDateRule: nodeSnapshot.startDateRule,
                          dateAdjustmentRule: nodeSnapshot.dateAdjustmentRule,
                          // 恢复节点计算状态
                          nodeCalculationState: nodeSnapshot.nodeCalculationState,
                          // 恢复连锁调整节点状态
                          chainAdjustmentNode: nodeSnapshot.chainAdjustmentNode
                        });
                      }
                    } catch (parseError) {
                      console.warn('解析节点快照失败:', parseError);
                    }
                  }
                }
              }
              
              // 按流程顺序排序节点快照
              nodeSnapshots.sort((a, b) => (a.processOrder || 0) - (b.processOrder || 0));
              
              console.log('收集到的节点快照数量:', nodeSnapshots.length);
              console.log('全局快照数据:', globalSnapshotData);
              
              // 验证数据完整性
              if (globalSnapshotData && globalSnapshotData.totalNodes && 
                  nodeSnapshots.length === globalSnapshotData.totalNodes) {
                
                // 重组完整的 timelineResults
                setTimelineResults(nodeSnapshots);
                setTimelineVisible(true);
                
                // 恢复智能缓冲期状态（如果存在）
                if (globalSnapshotData.bufferManagement) {
                  console.log('恢复智能缓冲期状态:', globalSnapshotData.bufferManagement);
                  // 这里可以添加额外的状态恢复逻辑，如果需要的话
                }
                
                // 恢复连锁调整系统状态（如果存在）
                if (globalSnapshotData.chainAdjustmentSystem) {
                  console.log('恢复连锁调整系统状态:', globalSnapshotData.chainAdjustmentSystem);
                  // 这里可以添加额外的状态恢复逻辑，如果需要的话
                }
                
                // 恢复生成模式状态（如果存在）
                if (globalSnapshotData.generationModeState) {
                  console.log('恢复生成模式状态:', globalSnapshotData.generationModeState);
                  const genState = globalSnapshotData.generationModeState;
                  
                  // 确保生成模式的关键状态被正确恢复
                  if (genState.currentForeignId && !currentForeignId) {
                    setCurrentForeignId(genState.currentForeignId);
                  }
                  if (genState.currentStyleText && !currentStyleText) {
                    setCurrentStyleText(genState.currentStyleText);
                  }
                  if (genState.currentColorText && !currentColorText) {
                    setCurrentColorText(genState.currentColorText);
                  }
                  if (genState.currentText2 && !currentText2) {
                    setCurrentText2(genState.currentText2);
                  }
                  if (genState.currentVersionNumber !== undefined && !currentVersionNumber) {
                    setCurrentVersionNumber(genState.currentVersionNumber);
                  }
                }
                
                // 恢复时间线计算状态（如果存在）
                if (globalSnapshotData.timelineCalculationState) {
                  console.log('恢复时间线计算状态:', globalSnapshotData.timelineCalculationState);
                }

                if (bitable.ui.showToast) {
                  await bitable.ui.showToast({ 
                    toastType: 'success', 
                    message: `已从 ${nodeSnapshots.length} 个节点快照还原完整流程数据（包含智能缓冲期和连锁调整状态）` 
                  });
                }
                setTimelineLoading(false);
                setIsRestoringSnapshot(false); // 快照还原完成
                return; // 快照还原完成，退出函数
              } else {
                console.warn('快照数据不完整，降级为基于字段的还原');
                console.log('期望节点数:', globalSnapshotData?.totalNodes, '实际节点数:', nodeSnapshots.length);
              }
              
            } catch (collectError) {
              console.warn('收集节点快照数据失败，降级为基于字段的还原:', collectError);
            }
          }
        }
      } catch (snapError) {
        console.warn('解析快照失败，降级为基于字段的还原:', snapError);
        setIsRestoringSnapshot(false); // 快照还原失败，重置标志
      }

      // 如果到达这里，说明没有成功的快照还原，重置标志
      setIsRestoringSnapshot(false);

      const results = records.map((rec: any) => {
        const fields = rec?.fields || {};
        const processOrder = fields[PROCESS_ORDER_FIELD_ID_DATA];
        const nodeName = fields[PROCESS_NAME_FIELD_ID];
        const startTs = fields[ESTIMATED_START_DATE_FIELD_ID];
        const endTs = fields[ESTIMATED_END_DATE_FIELD_ID];
        const startDate = typeof startTs === 'number' ? new Date(startTs) : (startTs ? new Date(startTs) : null);
        const endDate = typeof endTs === 'number' ? new Date(endTs) : (endTs ? new Date(endTs) : null);
        return {
          processOrder: typeof processOrder === 'number' ? processOrder : parseInt(processOrder) || undefined,
          nodeName: typeof nodeName === 'string' ? nodeName : (nodeName?.text || ''),
          estimatedStart: startDate ? format(startDate, DATE_FORMATS.STORAGE_FORMAT) : '未找到时效数据',
          estimatedEnd: endDate ? format(endDate, DATE_FORMATS.STORAGE_FORMAT) : '未找到时效数据',
          timelineRecordId: rec?.id || rec?.recordId || null,
          timelineValue: undefined,
          calculationMethod: undefined,
          weekendDaysConfig: [],
          matchedLabels: [],
          skippedWeekends: 0,
          actualDays: undefined,
          startDateRule: undefined,
          dateAdjustmentRule: undefined,
          ruleDescription: undefined,
          adjustmentDescription: undefined
        };
      });

      // 如果没有快照恢复起始时间，则从当前货期记录中获取起始时间
      const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
      if (startTimeValue) {
        let extractedStartTime: Date | null = null;
        if (typeof startTimeValue === 'number') {
          extractedStartTime = new Date(startTimeValue);
        } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
          const timestamp = startTimeValue[0];
          if (typeof timestamp === 'number') {
            extractedStartTime = new Date(timestamp);
          }
        }
        
        if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
          setStartTime(extractedStartTime);
        }
      }

      const sorted = results.sort((a, b) => (a.processOrder || 0) - (b.processOrder || 0));
      setTimelineResults(sorted);
      setTimelineVisible(true);

      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'success', message: '已从货期记录还原流程数据' });
      }
    } catch (error) {
      console.error('从货期记录还原流程数据失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'error', message: `还原失败: ${(error as Error).message}` });
      }
    } finally {
      setTimelineLoading(false);
    }
  };

  // 流程数据表相关常量
  const PROCESS_DATA_TABLE_ID = 'tblsJzCxXClj5oK5'; // 流程数据表ID
  const FOREIGN_ID_FIELD_ID = 'fld3oxJmpr'; // foreign_id字段
  const PROCESS_NAME_FIELD_ID = 'fldR79qEG3'; // 流程名称字段
  const PROCESS_ORDER_FIELD_ID_DATA = 'fldmND6vjT'; // 流程顺序字段
  const ESTIMATED_START_DATE_FIELD_ID = 'fldlzvHjYP'; // 预计开始日期字段
  const ESTIMATED_END_DATE_FIELD_ID = 'fldaPtY7Jk'; // 预计完成日期字段
  const PROCESS_SNAPSHOT_JSON_FIELD_ID = 'fldSHTxfnC'; // 文本2：用于保存计算页面快照(JSON)
  const PROCESS_VERSION_FIELD_ID = 'fldwk5X7Yw'; // 版本字段
  const PROCESS_TIMELINESS_FIELD_ID = 'fldEYCXnWt'; // 时效字段（天）

  // 货期记录表相关常量
  const DELIVERY_RECORD_TABLE_ID = 'tblwiA49gksQrnfg'; // 货期记录表ID
  const DELIVERY_FOREIGN_ID_FIELD_ID = 'fld0gAIcHS'; // foreign_id字段（需要替换为实际字段ID）
  const DELIVERY_LABELS_FIELD_ID = 'fldp0cDP2T'; // 标签汇总字段（需要替换为实际字段ID）
  const DELIVERY_STYLE_FIELD_ID = 'fldJRFxwB1'; // 款式字段（需要替换为实际字段ID）
  const DELIVERY_COLOR_FIELD_ID = 'fldhA1uBMy'; // 颜色字段（需要替换为实际字段ID）
  const DELIVERY_CREATE_TIME_FIELD_ID = 'fldP4w79LQ'; // 生成时间字段（需要替换为实际字段ID）
  const DELIVERY_EXPECTED_DATE_FIELD_ID = 'fldrjlzsxn'; // 预计交付日期字段（需要替换为实际字段ID）
  const DELIVERY_NODE_DETAILS_FIELD_ID = 'fldu1KL9yC'; // 节点详情字段（需要替换为实际字段ID）
  const DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID = 'fldYNluU8D'; // 客户期望日期字段
  const DELIVERY_ADJUSTMENT_INFO_FIELD_ID = 'fldNc6nNsz'; // 货期调整信息字段（需要替换为实际字段ID）
  const DELIVERY_VERSION_FIELD_ID = 'fld5OmvZrn'; // 版本字段（新增）
  const DELIVERY_SNAPSHOT_JSON_FIELD_ID = 'fldEYIvHeP'; // 货期记录表：完整快照(JSON)
  // 起始时间字段（货期记录表新增）
  const DELIVERY_START_TIME_FIELD_ID = 'fld727qCAv';
  // 文本2字段（货期记录表新增）
  const DELIVERY_TEXT2_FIELD_ID = 'fldG6LZnmU';

  // 已移除中国法定节假日相关常量和配置

  // 这个变量声明也不需要了
  // const nodeNameToOptionId = new Map();

  // 统一的日期格式化函数
  const formatDate = (date: Date | string, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_WITH_TIME'): string => {
    try {
      if (!date) return '';
      
      const dateObj = typeof date === 'string' ? parseDate(date) : date;
      if (!dateObj || isNaN(dateObj.getTime())) {
        return '';
      }
      
      return format(dateObj, DATE_FORMATS[formatType], { locale: zhCN });
    } catch (error) {
      console.error('日期格式化失败:', error, { date, formatType });
      return '';
    }
  };

  // 统一的日期解析函数
  const parseDate = (dateStr: string): Date | null => {
    try {
      if (!dateStr || dateStr.includes('未找到') || dateStr.includes('时效值为0')) {
        return null;
      }
      
      // 如果是时间戳格式，直接转换
      if (/^\d{13}$/.test(dateStr)) {
        const date = new Date(parseInt(dateStr));
        if (!isNaN(date.getTime())) {
          return date;
        }
      }
      
      // 移除所有星期信息（支持"星期X"和"周X"格式）
      let cleanStr = dateStr
        .replace(/\s*星期[一二三四五六日天]\s*/g, ' ')
        .replace(/\s*周[一二三四五六日天]\s*/g, ' ')
        .replace(/\s+/g, ' ')
        .trim();
      
      // 处理可能的格式问题：如果日期和时间连在一起了，添加空格
      cleanStr = cleanStr.replace(/(\d{4}-\d{2}-\d{2})(\d{2}:\d{2})/, '$1 $2');
      
      // 尝试标准解析
      let date = new Date(cleanStr);
      if (!isNaN(date.getTime())) {
        return date;
      }
      
      // 手动解析 "YYYY-MM-DD HH:mm" 或 "YYYY-MM-DD HH:mm:ss" 格式
      const match = cleanStr.match(/(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2})(?::(\d{2}))?)?/);
      if (match) {
        const [, year, month, day, hour = '0', minute = '0', second = '0'] = match;
        return new Date(
          parseInt(year), 
          parseInt(month) - 1, 
          parseInt(day), 
          parseInt(hour), 
          parseInt(minute), 
          parseInt(second)
        );
      }
      
      throw new Error(`无法解析日期格式: ${cleanStr}`);
    } catch (error) {
      console.error('日期解析失败:', { dateStr, error: error.message });
      return null;
    }
  };

  // 获取星期几（统一格式）
  const getDayOfWeek = (dateStr: string | Date): string => {
    try {
      const date = typeof dateStr === 'string' ? parseDate(dateStr) : dateStr;
      if (!date || isNaN(date.getTime())) {
        return '';
      }
      return WEEKDAYS[date.getDay()];
    } catch (error) {
      console.error('获取星期失败:', error, { dateStr });
      return '';
    }
  };

  // 重构计算实际跨度天数函数
  const calculateActualDays = (startDateStr: string | Date, endDateStr: string | Date): number => {
    try {
      const startDate = typeof startDateStr === 'string' ? parseDate(startDateStr) : startDateStr;
      const endDate = typeof endDateStr === 'string' ? parseDate(endDateStr) : endDateStr;
      
      if (!startDate || !endDate || isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
        console.log('日期解析失败:', { startDateStr, endDateStr, startDate, endDate });
        return 0;
      }
      
      // 计算日期差异（只考虑日期部分）
      const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
      const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
      
      const diffTime = endDateOnly.getTime() - startDateOnly.getTime();
      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
      
      console.log('自然日计算:', { 
        startDateStr: formatDate(startDate), 
        endDateStr: formatDate(endDate), 
        diffDays 
      });
      
      return Math.max(0, diffDays);
    } catch (error) {
      console.error('计算自然日出错:', error, { startDateStr, endDateStr });
      return 0;
    }
  };

  // 计算跳过的周末天数 - 支持空的休息日配置
  const calculateSkippedWeekends = (startDate: Date | string, endDate: Date | string, weekendDays: number[] = []): number => {
    if (weekendDays.length === 0) return 0; // 如果没有配置休息日，则不跳过任何天数
    
    try {
      const start = typeof startDate === 'string' ? new Date(startDate) : startDate;
      const end = typeof endDate === 'string' ? new Date(endDate) : endDate;
      
      if (isNaN(start.getTime()) || isNaN(end.getTime())) {
        return 0;
      }
      
      let count = 0;
      const current = new Date(start);
      
      while (current <= end) {
        if (weekendDays.includes(current.getDay())) {
          count++;
        }
        current.setDate(current.getDate() + 1);
      }
      
      return count;
    } catch (error) {
      return 0;
    }
  };

  // 计算时间范围内实际跳过的自定义日期
  const calculateExcludedDatesInRange = (startDate: Date | string, endDate: Date | string, excludedDates: string[] = []): { count: number, dates: string[] } => {
    if (!excludedDates || excludedDates.length === 0) {
      return { count: 0, dates: [] };
    }
    
    try {
      const start = typeof startDate === 'string' ? parseDate(startDate) : startDate;
      const end = typeof endDate === 'string' ? parseDate(endDate) : endDate;
      
      if (!start || !end || isNaN(start.getTime()) || isNaN(end.getTime())) {
        return { count: 0, dates: [] };
      }
      
      const actualExcludedDates: string[] = [];
      
      for (const excludedDateStr of excludedDates) {
        const excludedDate = parseDate(excludedDateStr);
        if (excludedDate && excludedDate >= start && excludedDate <= end) {
          actualExcludedDates.push(excludedDateStr);
        }
      }
      
      return { count: actualExcludedDates.length, dates: actualExcludedDates };
    } catch (error) {
      console.error('计算跳过日期失败:', error);
      return { count: 0, dates: [] };
    }
  };

  // 已移除法定节假日跳过统计函数

  // 已移除中国节假日判断函数

  // 判断是否为自定义周末 - 支持空的休息日配置
  const isCustomWeekend = (date: Date, weekendDays: number[] = []): boolean => {
    if (weekendDays.length === 0) return false; // 如果没有配置休息日，则不认为是周末
    return weekendDays.includes(date.getDay());
  };

  // 判断是否为工作日 - 排除表格休息日、以及节点自定义不参与计算日期
  const isBusinessDay = (date: Date, weekendDays: number[] = [], excludedDates: string[] = []): boolean => {
    try {
      const dateStr = format(date, 'yyyy-MM-dd');
      const isExcluded = Array.isArray(excludedDates) && excludedDates.includes(dateStr);
      return !isCustomWeekend(date, weekendDays) && !isExcluded;
    } catch {
      return !isCustomWeekend(date, weekendDays);
    }
  };

  // 日期调整函数
  const adjustStartDateByRule = (date: Date, ruleJson: string): Date => {
    if (!ruleJson || ruleJson.trim() === '') {
      return date;
    }
    
    try {
      const config = JSON.parse(ruleJson);
      const adjustedDate = new Date(date);
      const currentDayOfWeek = adjustedDate.getDay(); // 0=周日, 1=周一, ..., 6=周六
      
      // 转换为1-7格式（1=周一, 7=周日）
      const dayOfWeek = currentDayOfWeek === 0 ? 7 : currentDayOfWeek;
      
      if (config.rules && Array.isArray(config.rules)) {
        for (const rule of config.rules) {
          if (rule.condition === 'dayOfWeek' && rule.value === dayOfWeek) {
            if (rule.action === 'delayToNextWeek') {
              // 计算下周目标日期
              const targetDay = rule.targetDay || 1; // 默认周一
              const daysToAdd = 7 - dayOfWeek + targetDay;
              adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
              
              console.log(`应用规则: ${rule.description || '未知规则'}, 原日期: ${format(date, 'yyyy-MM-dd')}, 调整后: ${format(adjustedDate, 'yyyy-MM-dd')}`);
              break; // 只应用第一个匹配的规则
            }
          }
        }
      }
      
      return adjustedDate;
    } catch (error) {
      console.error('解析日期调整规则失败:', error);
      return date; // 解析失败时返回原日期
    }
  };

  // JSON格式日期调整函数 - 修改为返回调整结果和描述
  const adjustStartDateByJsonRule = (date: Date, ruleJson: string): { adjustedDate: Date, description?: string } => {
    if (!ruleJson || ruleJson.trim() === '') {
      return { adjustedDate: date };
    }
    
    try {
      const rules = JSON.parse(ruleJson);
      const dayOfWeek = date.getDay(); // 0=周日, 1=周一, ..., 6=周六
      const dayKey = dayOfWeek === 0 ? '7' : dayOfWeek.toString(); // 转换为1-7格式
      
      const rule = rules[dayKey];
      if (!rule) {
        return { adjustedDate: date }; // 没有匹配的规则，返回原日期
      }
      
      const adjustedDate = new Date(date);
      let description = rule.description || '';
      
      switch (rule.action) {
        case 'delayInSameWeek':
          // 在本周内延期到指定星期几
          const targetDay = rule.targetDay;
          const currentDay = dayOfWeek === 0 ? 7 : dayOfWeek; // 转换为1-7格式
          
          if (targetDay > currentDay) {
            // 延期到本周的目标日期
            adjustedDate.setDate(adjustedDate.getDate() + (targetDay - currentDay));
          } else {
            // 如果目标日期已过，延期到下周的目标日期
            adjustedDate.setDate(adjustedDate.getDate() + (7 - currentDay + targetDay));
          }
          break;
          
        case 'delayToNextWeek':
          // 延期到下周的指定星期几
          const nextWeekTargetDay = rule.targetDay;
          const daysToAdd = 7 - (dayOfWeek === 0 ? 7 : dayOfWeek) + nextWeekTargetDay;
          adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
          break;
          
        case 'delayDays':
          // 直接延期指定天数
          const delayDays = rule.days || 0;
          adjustedDate.setDate(adjustedDate.getDate() + delayDays);
          break;
          
        default:
          console.warn(`未知的调整动作: ${rule.action}`);
          break;
      }
      
      console.log(`应用调整规则: ${dayKey} -> ${JSON.stringify(rule)}, 原日期: ${date.toDateString()}, 调整后: ${adjustedDate.toDateString()}`);
      return { adjustedDate, description };
      
    } catch (error) {
      console.error('解析日期调整规则失败:', error, '规则内容:', ruleJson);
      return { adjustedDate: date }; // 解析失败时返回原日期
    }
  };

  // 调整到下一个工作时间开始点
  const adjustToNextWorkingHour = (date: Date, calculationMethod: string, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(date);
    
    if (calculationMethod === '内部') {
      const hour = result.getHours();
      const minute = result.getMinutes();
      
      // 如果是工作时间外（18:00之后或9:00之前），调整到下一个工作日的9:00
      if (hour >= 18 || hour < 9) {
        // 如果是当天18:00之后，调整到下一个工作日
        if (hour >= 18) {
          result.setDate(result.getDate() + 1);
        }
        
        // 找到下一个工作日（考虑休息日和自定义跳过日期）
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        
        // 设置为9:00:00
        result.setHours(9, 0, 0, 0);
      }
    }
    
    return result;
  };

  // 内部工作时间计算函数
  const addInternalBusinessTime = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(startDate);
    let remainingDays = businessDays;
    
    // 处理整数天
    const wholeDays = Math.floor(remainingDays);
    let addedDays = 0;
    
    while (addedDays < wholeDays) {
      result.setDate(result.getDate() + 1);
      if (isBusinessDay(result, weekendDays, excludedDates)) {
        addedDays++;
      }
    }
    
    // 处理小数部分（按9小时工作制）
    const fractionalDays = remainingDays - wholeDays;
    if (fractionalDays > 0) {
      const workingHoursToAdd = fractionalDays * 9; // 内部按9小时工作制
      let currentHour = result.getHours();
      let currentMinute = result.getMinutes();
      
      // 确保在工作时间内开始
      if (currentHour < 9) {
        currentHour = 9;
        currentMinute = 0;
      } else if (currentHour >= 18) {
        // 跳到下一个工作日的9:00
        result.setDate(result.getDate() + 1);
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        currentHour = 9;
        currentMinute = 0;
      }
      
      // 添加工作小时
      const totalMinutes = currentHour * 60 + currentMinute + workingHoursToAdd * 60;
      const finalHour = Math.floor(totalMinutes / 60);
      const finalMinute = totalMinutes % 60;
      
      // 如果超过18:00，需要跨到下一个工作日
      if (finalHour >= 18) {
        const overflowHours = finalHour - 18;
        const overflowMinutes = finalMinute;
        
        // 跳到下一个工作日
        result.setDate(result.getDate() + 1);
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        
        result.setHours(9 + overflowHours, overflowMinutes, 0, 0);
      } else {
        result.setHours(finalHour, finalMinute, 0, 0);
      }
    }
    
    return result;
  };

  // 添加工作日 - 使用表格配置的休息日与节点自定义跳过日期
  const addBusinessDaysWithHolidays = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(startDate);
    let addedDays = 0;
    
    // 处理小数天数：先添加整数天，再处理小数部分
    const wholeDays = Math.floor(businessDays);
    const fractionalDays = businessDays - wholeDays;
    
    // 添加整数工作日
    while (addedDays < wholeDays) {
      result.setDate(result.getDate() + 1);
      if (isBusinessDay(result, weekendDays, excludedDates)) {
        addedDays++;
      }
    }
    
    // 处理小数部分（转换为小时，按24小时制）
    if (fractionalDays > 0) {
      const hoursToAdd = fractionalDays * 24; // 1天=24小时
      result.setHours(result.getHours() + hoursToAdd);
    }
    
    return result;
  };



  // 获取标签数据
  const fetchLabelOptions = async () => {
    setLabelLoading(true);
    try {
      // 获取标签表
      const labelTable = await bitable.base.getTable(LABEL_TABLE_ID);
      
      // 1. 先获取所有字段的元数据
      const fieldMetaList = await labelTable.getFieldMetaList();
      
      // 2. 筛选出标签1-标签10的字段
      const labelFields: {[key: string]: string} = {}; // 存储字段名到字段ID的映射
      
      for (const fieldMeta of fieldMetaList) {
        // 检查字段名是否匹配标签1-标签10的模式
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          labelFields[labelKey] = fieldMeta.id;
        }
      }
      
      console.log('找到的标签字段:', labelFields);
      
      // 3. 处理标签数据 - 从字段选项获取而不是从记录数据获取
      const options: {[key: string]: any[]} = {};
      
      // 初始化十个标签的选项数组
      for (let i = 1; i <= 10; i++) {
        options[`标签${i}`] = [];
      }
      
      // 4. 遍历标签字段，获取每个字段的选项
      for (const [labelKey, fieldId] of Object.entries(labelFields)) {
        try {
          const field = await labelTable.getField(fieldId);
          const fieldMeta = await field.getMeta();
          
          // 检查是否是选择字段（单选或多选）
          if (fieldMeta.type === FieldType.SingleSelect || fieldMeta.type === FieldType.MultiSelect) {
            const selectField = field as any; // 类型断言
            const fieldOptions = await selectField.getOptions();
            
            // 转换为我们需要的格式
            options[labelKey] = fieldOptions.map((option: any) => ({
              label: option.name,
              value: option.name
            }));
          }
        } catch (error) {
          console.warn(`获取${labelKey}字段选项失败:`, error);
          // 如果获取选项失败，保持空数组
          options[labelKey] = [];
        }
      }
      
      console.log('处理后的标签选项:', options);
      
      setLabelOptions(options);
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: `标签选项加载成功，共找到 ${Object.keys(labelFields).length} 个标签字段`
        });
      }
    } catch (error) {
      console.error('获取标签选项失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '获取标签选项失败，请检查表格配置'
        });
      }
    } finally {
      setLabelLoading(false);
    }
  };

  // 组件加载时获取标签数据和初始化起始时间
  useEffect(() => {
    const initializeData = async () => {
      await fetchLabelOptions();
      await initializeStartTime();
      await loadAvailableTables(); // 加载可用表列表
    };
    
    initializeData();
  }, []);

  // 初始化起始时间：从货期记录表获取，新记录则使用当前时间
  const initializeStartTime = async () => {
    try {
      const selection = await bitable.base.getSelection();
      const recordId = selection?.recordId || '';
      const tableId = selection?.tableId || '';
      
      if (recordId && tableId === DELIVERY_RECORD_TABLE_ID) {
        // 如果选中的是货期记录表的记录，从中获取起始时间
        const deliveryTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
        const deliveryRecord = await deliveryTable.getRecordById(recordId);
        const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
        
        if (startTimeValue) {
          let extractedStartTime: Date | null = null;
          if (typeof startTimeValue === 'number') {
            extractedStartTime = new Date(startTimeValue);
          } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
            const timestamp = startTimeValue[0];
            if (typeof timestamp === 'number') {
              extractedStartTime = new Date(timestamp);
            }
          }
          
          if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
            setStartTime(extractedStartTime);
            return;
          }
        }
      }
      
      // 如果没有找到有效的起始时间，使用当前时间
      setStartTime(new Date());
    } catch (error) {
      console.error('初始化起始时间失败:', error);
      // 出错时使用当前时间作为默认值
      setStartTime(new Date());
    }
  };

  // 加载可用表列表
  const loadAvailableTables = async () => {
    try {
      setTablesLoading(true);
      const tableMetaList = await bitable.base.getTableMetaList();
      const tables = tableMetaList.map(table => ({
        id: table.id,
        name: table.name
      }));
      setAvailableTables(tables);
    } catch (error) {
      console.error('加载表列表失败:', error);
    } finally {
      setTablesLoading(false);
    }
  };

  // 加载指定表的视图列表
  const loadAvailableViews = async (tableId: string) => {
    if (!tableId) {
      setAvailableViews([]);
      return;
    }
    
    try {
      setViewsLoading(true);
      const table = await bitable.base.getTable(tableId);
      const viewMetaList = await table.getViewMetaList();
      const views = viewMetaList.map(view => ({
        id: view.id,
        name: view.name
      }));
      setAvailableViews(views);
    } catch (error) {
      console.error('加载视图列表失败:', error);
      setAvailableViews([]);
    } finally {
      setViewsLoading(false);
    }
  };

  // 处理表选择变化
  const handleBatchTableChange = (tableId: string) => {
    // 切换批量来源表时重置全局变量，避免旧状态残留
    resetGlobalState();
    setSelectedBatchTableId(tableId);
    setSelectedBatchViewId(''); // 重置视图选择
    loadAvailableViews(tableId); // 加载新表的视图列表
  };

  // 处理标签选择变化
  const handleLabelChange = (labelKey: string, value: string | string[]) => {
    setSelectedLabels(prev => ({
      ...prev,
      [labelKey]: value
    }));
  };

  // 清空标签选择
  const handleClearLabels = () => {
    setSelectedLabels({});
    setExpectedDate(null); // 清空客户期望日期
  };
  
  // 计算预计开始和完成时间
  const handleCalculateTimeline = async (
    skipValidation: boolean = false,
    overrideData?: {
      selectedRecords?: string[],
      recordDetails?: any[],
      selectedLabels?: {[key: string]: string | string[]},
      expectedDate?: Date | null,
      startTime?: Date | null
    },
    showUI: boolean = true // 新增参数控制是否显示UI
  ) => {
    // 使用传入的数据或全局状态
    const currentSelectedRecords = overrideData?.selectedRecords || selectedRecords;
    const currentRecordDetails = overrideData?.recordDetails || recordDetails;
    const currentSelectedLabels = overrideData?.selectedLabels || selectedLabels;
    const currentExpectedDate = overrideData?.expectedDate || expectedDate;
    const currentStartTime = overrideData?.startTime || startTime;
    
    console.log('=== handleCalculateTimeline - 使用的数据 ===');
    console.log('currentSelectedRecords:', currentSelectedRecords);
    console.log('currentSelectedLabels:', currentSelectedLabels);
    console.log('currentExpectedDate:', currentExpectedDate);
    console.log('currentStartTime:', currentStartTime);
    
    // 跳过验证（用于批量模式）
    if (!skipValidation) {
      // 检查是否选择了多条记录
      if (currentSelectedRecords.length > 1) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '计算时效功能仅支持单条记录，请重新选择单条记录后再试'
          });
        }
        return;
      }
      
      // 检查是否选择了记录
      if (currentSelectedRecords.length === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '请先选择一条记录'
          });
        }
        return;
      }
      
      // 检查是否选择了标签
      const hasSelectedLabels = Object.values(currentSelectedLabels).some(value => {
        return Array.isArray(value) ? value.length > 0 : Boolean(value);
      });
    
      if (!hasSelectedLabels) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '请先选择至少一个标签'
          });
        }
        return;
      }
    
      // 可选：检查是否选择了客户期望日期
      if (!currentExpectedDate) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'info',
            message: '建议选择客户期望日期以便更好地进行时效计算'
          });
        }
      }
    }
  
    // 移除冗余日志：客户期望日期输出
    setTimelineLoading(true);
    // 生成模式：输出当前数据结构，便于与批量模式对比
    try {
      console.group('=== 生成模式：计算时效 - 当前数据结构 ===');
      // 模式与核心输入
      console.log('mode:', mode);
      console.log('selectedRecords:', currentSelectedRecords);
      console.log('recordDetails:', currentRecordDetails);
      console.log('selectedLabels:', currentSelectedLabels);
      console.log('expectedDate:', currentExpectedDate);
      console.groupEnd();
    } catch (logErr) {
      console.warn('生成模式结构化日志输出失败:', logErr);
    }
    try {
      // 构建业务选择的所有标签值集合（用于快速查找）
      const businessLabelValues = new Set<string>();
      for (const [labelKey, selectedValue] of Object.entries(currentSelectedLabels)) {
        if (selectedValue) {
          const values = Array.isArray(selectedValue) ? selectedValue : [selectedValue];
          values.forEach(value => {
            if (typeof value === 'string' && value.trim()) {
              businessLabelValues.add(value.trim());
            }
          });
        }
      }
      
      // 已移除冗余日志：业务选择标签值
      const timelineTable = await bitable.base.getTable(TIMELINE_TABLE_ID);
      const timelineFieldMetaList = await timelineTable.getFieldMetaList();
      const timelineLabelFields: {[key: string]: string} = {};
      
      // 构建时效表的标签字段映射（只执行一次）
      let relationshipFieldId = ''; // 关系字段ID
      let calculationMethodFieldId = ''; // 时效计算方式字段ID
      
      for (const fieldMeta of timelineFieldMetaList) {
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          timelineLabelFields[labelKey] = fieldMeta.id;
        }
        // 查找关系字段
        if (fieldMeta.name === '关系' || fieldMeta.id === 'fldaIDAhab') {
          relationshipFieldId = fieldMeta.id;
        }
        // 查找时效计算方式字段
        if (fieldMeta.name === '时效计算方式' || fieldMeta.id === 'fldxfLZNUu') {
          calculationMethodFieldId = fieldMeta.id;
        }
      }
      
      console.log('时效表标签字段映射:', timelineLabelFields);
      console.log('关系字段ID:', relationshipFieldId);
      
      // 1. 先获取匹配的流程节点（复用预览功能的逻辑）
      const processTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      const processRecordsResult = await processTable.getRecords({
        pageSize: 5000
      });
      
      const processRecords = processRecordsResult.records || [];
      const matchedProcessNodes: any[] = [];
      
      // 匹配流程配置节点
      for (const record of processRecords) {
        const fields = record.fields;
        const processLabels = fields[PROCESS_LABEL_FIELD_ID];
        const nodeName = fields[NODE_NAME_FIELD_ID];
        const processOrder = fields[PROCESS_ORDER_FIELD_ID]; // 获取流程顺序
        
        if (!processLabels || !nodeName) continue;
        
        // 处理流程配置表中的标签数据 - 修复多选字段处理
        let processLabelTexts: string[] = [];
        if (typeof processLabels === 'string') {
          processLabelTexts = [processLabels];
        } else if (processLabels && processLabels.text) {
          processLabelTexts = [processLabels.text];
        } else if (Array.isArray(processLabels) && processLabels.length > 0) {
          // 处理多选字段，获取所有选项的值
          processLabelTexts = processLabels.map(item => {
            if (typeof item === 'string') {
              return item;
            } else if (item && item.text) {
              return item.text;
            } else if (item && item.value) {
              return item.value;
            }
            return String(item);
          }).filter(text => text && text.trim());
        }
        
        // 处理节点名称
        let nodeNameText = '';
        if (typeof nodeName === 'string') {
          nodeNameText = nodeName;
        } else if (nodeName.text) {
          nodeNameText = nodeName.text;
        }
        
        // 处理流程顺序
        let orderValue = 0;
        if (typeof processOrder === 'number') {
          orderValue = processOrder;
        } else if (typeof processOrder === 'string') {
          orderValue = parseInt(processOrder) || 0;
        } else if (processOrder && processOrder.value !== undefined) {
          orderValue = processOrder.value;
        }
        
        if (processLabelTexts.length === 0 || !nodeNameText) continue;
        
        // 检查是否匹配当前选择的标签 - 修复匹配逻辑
        let isMatched = false;
        const matchedLabels: string[] = [];
        
        for (const [labelKey, labelValue] of Object.entries(currentSelectedLabels)) {
          if (!labelValue) continue;
          
          const valuesToCheck = Array.isArray(labelValue) ? labelValue : [labelValue];
          
          for (const value of valuesToCheck) {
            // 检查用户选择的值是否在流程配置的任何一个标签选项中
            const isValueMatched = processLabelTexts.some(processLabelText => {
              // 直接匹配
              if (processLabelText === value) {
                return true;
              }
              // 包含匹配（用于处理可能的格式差异）
              if (processLabelText.includes(value)) {
                return true;
              }
              return false;
            });
            
            if (isValueMatched) {
              isMatched = true;
              matchedLabels.push(`${labelKey}: ${value}`);
              console.log(`匹配成功: ${labelKey} = ${value}`);
            } else {
              console.log(`匹配失败: ${labelKey} = ${value}, 流程配置标签: [${processLabelTexts.join(', ')}]`);
            }
          }
        }
        
        // 处理休息日配置 - 完全从表格字段获取
        let weekendDays: number[] = [];
        const weekendDaysField = fields[WEEKEND_DAYS_FIELD_ID]; // 获取休息日配置
        if (weekendDaysField) {
          console.log('原始休息日字段数据:', weekendDaysField);
          
          if (Array.isArray(weekendDaysField)) {
            // 多选字段返回数组，每个元素可能是选项对象
            weekendDays = weekendDaysField.map(item => {
              // 处理选项对象 {id: "xxx", text: "0"} 或直接的值
              if (item && typeof item === 'object') {
                // 如果是选项对象，取text或id字段
                const value = item.text || item.id || item.value;
                if (typeof value === 'string') {
                  const parsed = parseInt(value);
                  return !isNaN(parsed) && parsed >= 0 && parsed <= 6 ? parsed : null;
                } else if (typeof value === 'number') {
                  return value >= 0 && value <= 6 ? value : null;
                }
              } else if (typeof item === 'string') {
                const parsed = parseInt(item);
                return !isNaN(parsed) && parsed >= 0 && parsed <= 6 ? parsed : null;
              } else if (typeof item === 'number') {
                return item >= 0 && item <= 6 ? item : null;
              }
              return null;
            }).filter(day => day !== null) as number[];
          } else if (typeof weekendDaysField === 'string') {
            // 如果是字符串，尝试解析
            try {
              const parsed = JSON.parse(weekendDaysField);
              if (Array.isArray(parsed)) {
                weekendDays = parsed.filter(day => typeof day === 'number' && day >= 0 && day <= 6);
              }
            } catch {
              // 如果解析失败，尝试按逗号分割
              const parts = weekendDaysField.split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n) && n >= 0 && n <= 6);
              if (parts.length > 0) {
                weekendDays = parts;
              }
            }
          } else if (typeof weekendDaysField === 'number' && weekendDaysField >= 0 && weekendDaysField <= 6) {
            weekendDays = [weekendDaysField];
          }
          
          console.log('解析后的休息日配置:', weekendDays);
        }
        // 如果表格中没有配置休息日或配置为空，则该节点没有固定休息日
        // 这样就完全依赖表格数据，不会有任何硬编码的默认值
        
        // 处理不参与计算日期（自定义跳过日期）
        let excludedDates: string[] = [];
        const excludedDatesField = fields[EXCLUDED_DATES_FIELD_ID];
        if (excludedDatesField) {
          console.log('原始不参与计算日期字段数据:', excludedDatesField);
          if (Array.isArray(excludedDatesField)) {
            excludedDates = excludedDatesField.map(item => {
              if (item && typeof item === 'object') {
                const val = item.text || item.name || item.value || item.id || '';
                return String(val).trim();
              }
              return String(item).trim();
            }).filter(d => !!d);
          } else if (typeof excludedDatesField === 'string') {
            excludedDates = excludedDatesField.split(/[\,\s]+/).map(s => s.trim()).filter(Boolean);
          } else if (excludedDatesField && typeof excludedDatesField === 'object' && excludedDatesField.text) {
            excludedDates = [String(excludedDatesField.text).trim()].filter(Boolean);
          }
          console.log('解析后的不参与计算日期:', excludedDates);
        }
        
        if (isMatched) {
          // 获取起始日期调整规则
          const startDateRule = fields[START_DATE_RULE_FIELD_ID];
          // 获取JSON格式的日期调整规则
          const dateAdjustmentRule = fields[DATE_ADJUSTMENT_RULE_FIELD_ID];
          
          matchedProcessNodes.push({
            id: record.id,
            nodeName: nodeNameText,
            processLabels: processLabelTexts.join(', '),
            matchedLabels: matchedLabels,
            processOrder: orderValue, // 添加流程顺序
            weekendDays: weekendDays, // 添加休息日配置
            excludedDates: excludedDates, // 添加自定义跳过日期
            startDateRule: startDateRule, // 添加起始日期调整规则
            dateAdjustmentRule: dateAdjustmentRule // 添加JSON格式日期调整规则
          });
        }
      }
      
      // 按流程顺序排序
      matchedProcessNodes.sort((a, b) => a.processOrder - b.processOrder);
      
      console.log('按顺序排列的流程节点:', matchedProcessNodes);
      
      // 2. 优化：预先获取所有时效数据并建立索引
      const timelineRecordsResult = await timelineTable.getRecords({
        pageSize: 5000
      });
      
      const timelineRecords = timelineRecordsResult.records || [];
      
      // 优化2：预处理时效数据，建立节点名称到记录的映射
      const timelineIndexByNode = new Map<string, any[]>();
      
      for (const timelineRecord of timelineRecords) {
        const timelineFields = timelineRecord.fields;
        const timelineNodeName = timelineFields[TIMELINE_NODE_FIELD_ID];
        
        // 处理时效表中的节点名称
        let timelineNodeNames: string[] = [];
        
        if (typeof timelineNodeName === 'string') {
          timelineNodeNames = timelineNodeName.split(',').map(name => name.trim());
        } else if (Array.isArray(timelineNodeName)) {
          timelineNodeNames = timelineNodeName.map(item => {
            if (typeof item === 'string') {
              return item.trim();
            } else if (item && item.text) {
              return item.text.trim();
            }
            return '';
          }).filter(name => name);
        } else if (timelineNodeName && timelineNodeName.text) {
          timelineNodeNames = timelineNodeName.text.split(',').map(name => name.trim());
        }
        
        // 为每个节点名称建立索引
        for (const nodeName of timelineNodeNames) {
          const normalizedName = nodeName.toLowerCase();
          if (!timelineIndexByNode.has(normalizedName)) {
            timelineIndexByNode.set(normalizedName, []);
          }
          timelineIndexByNode.get(normalizedName)!.push({
            record: timelineRecord,
            fields: timelineFields
          });
        }
      }
      
      console.log('时效数据索引构建完成，节点数量:', timelineIndexByNode.size);
      
      const results: any[] = [];
      
      // 3. 按顺序为每个匹配的流程节点查找时效数据并计算累积时间
      let cumulativeStartTime = currentStartTime ? new Date(currentStartTime) : new Date(); // 累积开始时间
      
      for (let i = 0; i < matchedProcessNodes.length; i++) {
        const processNode = matchedProcessNodes[i];
        let timelineValue = null;
        let matchedTimelineRecord = null;
        
        // 优化3：使用索引快速查找候选记录
        const normalizedProcessName = processNode.nodeName.trim().toLowerCase();
        const candidateRecords = timelineIndexByNode.get(normalizedProcessName) || [];
        
        console.log(`节点 ${processNode.nodeName} 找到 ${candidateRecords.length} 个候选时效记录`);
        
        // 在候选记录中进行标签匹配
        let matchedCandidates = []; // 收集所有匹配的候选记录
        
        for (const candidate of candidateRecords) {
          const { record: timelineRecord, fields: timelineFields } = candidate;
          
          // 优化4：使用预构建的字段映射进行标签匹配
          let isLabelsMatched = true;
          
          // 检查时效表中每个有值的标签是否都包含在业务标签中
          for (const [labelKey, timelineFieldId] of Object.entries(timelineLabelFields)) {
            const timelineLabelValue = timelineFields[timelineFieldId];
            
            // 处理时效表中的标签值
            let timelineLabelTexts: string[] = [];
            
            if (typeof timelineLabelValue === 'string' && timelineLabelValue.trim()) {
              timelineLabelTexts = [timelineLabelValue.trim()];
            } else if (timelineLabelValue && timelineLabelValue.text && timelineLabelValue.text.trim()) {
              timelineLabelTexts = [timelineLabelValue.text.trim()];
            } else if (Array.isArray(timelineLabelValue) && timelineLabelValue.length > 0) {
              // 多选字段，获取所有值
              timelineLabelTexts = timelineLabelValue.map(item => {
                if (typeof item === 'string') return item.trim();
                if (item && item.text) return item.text.trim();
                return '';
              }).filter(text => text);
            }
            
            // 如果时效表中该标签有值，则检查该标签的所有值是否都包含在业务标签中
            if (timelineLabelTexts.length > 0) {
              let allValuesMatched = true;
              
              // 优化5：使用Set的has方法进行快速查找
              for (const timelineText of timelineLabelTexts) {
                if (!businessLabelValues.has(timelineText)) {
                  allValuesMatched = false;
                  console.log(`时效表标签 ${labelKey} 的值 "${timelineText}" 不在业务选择的标签中`);
                  break;
                }
              }
              
              if (!allValuesMatched) {
                console.log(`时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 不完全包含在业务选择的标签中`);
                isLabelsMatched = false;
                break;
              } else {
                console.log(`时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 完全匹配成功`);
              }
            }
            // 如果时效表中该标签为空，则跳过检查（空标签不影响匹配）
          }
          
          // 只有标签匹配成功才获取时效数据
                if (isLabelsMatched) {
                  // 找到匹配的节点，获取时效值
                  const timelineValueField = timelineFields[TIMELINE_FIELD_ID];
                  // 获取关系字段值
                  const relationshipField = timelineFields[relationshipFieldId];
                  // 获取时效计算方式字段值
                  const calculationMethodField = timelineFields[calculationMethodFieldId];
                  
                  if (timelineValueField !== null && timelineValueField !== undefined) {
                    let candidateTimelineValue = 0;
                    
                    // 解析时效值
                    if (typeof timelineValueField === 'number') {
                      candidateTimelineValue = timelineValueField;
                    } else if (typeof timelineValueField === 'string') {
                      const parsedValue = parseFloat(timelineValueField);
                      candidateTimelineValue = isNaN(parsedValue) ? 0 : parsedValue;
                    } else if (timelineValueField && typeof timelineValueField === 'object' && timelineValueField.value !== undefined) {
                      candidateTimelineValue = timelineValueField.value;
                    }
                    
                    // 获取计算方式
                    let calculationMethod = '外部'; // 默认值
                    if (calculationMethodField) {
                      if (typeof calculationMethodField === 'string') {
                        calculationMethod = calculationMethodField;
                      } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
                        calculationMethod = calculationMethodField.text;
                      }
                    }
                    
                    // 根据计算方式转换时效值（小时转天）
                    let convertedTimelineValue = 0;
                    if (calculationMethod === '内部') {
                      convertedTimelineValue = Math.round((candidateTimelineValue / 9) * 1000) / 1000; // 精确到3位小数
                      console.log(`内部计算方式: ${candidateTimelineValue}小时 → ${convertedTimelineValue.toFixed(3)}天`);
                    } else {
                      convertedTimelineValue = Math.round((candidateTimelineValue / 24) * 1000) / 1000; // 精确到3位小数
                      console.log(`外部计算方式: ${candidateTimelineValue}小时 → ${convertedTimelineValue.toFixed(3)}天`);
                    }
                    
                    // 获取关系类型
                    let relationshipType = '默认';
                    if (relationshipField) {
                      if (typeof relationshipField === 'string') {
                        relationshipType = relationshipField;
                      } else if (relationshipField && typeof relationshipField === 'object' && relationshipField.text) {
                        relationshipType = relationshipField.text;
                      }
                    }
                    
                    // 调试时效记录对象结构
                    console.log('时效记录对象结构:', timelineRecord);
                    console.log('记录ID字段:', {
                      id: timelineRecord.id,
                      recordId: timelineRecord.recordId,
                      _id: timelineRecord._id,
                      record_id: timelineRecord.record_id
                    });
                    
                    matchedCandidates.push({
                      record: timelineRecord,
                      timelineValue: convertedTimelineValue, // 使用转换后的值
                      relationshipType: relationshipType,
                      calculationMethod: calculationMethod, // 记录计算方式
                      originalHours: candidateTimelineValue // 保留原始小时值用于日志
                    });
                    
                    // 移除单条记录的详细日志输出，避免日志冗余
                    // console.log(`节点 ${processNode.nodeName} 找到匹配记录:`, {
                    //   记录ID: timelineRecord.id || timelineRecord.recordId || timelineRecord._id || timelineRecord.record_id,
                    //   原始时效值小时: candidateTimelineValue,
                    //   转换后天数: convertedTimelineValue,
                    //   关系类型: relationshipType,
                    //   时效计算方式: calculationMethod
                    // });
                  }
                }
        }
        
        // 在 matchedCandidates 处理之前定义 processingRule
        let processingRule = '默认'; // 默认值
        
        // 根据关系字段和时效计算方式决定如何处理多个匹配的记录
        if (matchedCandidates.length > 0) {
          // 检查所有匹配记录的关系类型和计算方式
          const relationshipTypes = [...new Set(matchedCandidates.map(c => c.relationshipType))];
          const calculationMethods = [...new Set(matchedCandidates.map(c => c.calculationMethod))];
          
          if (relationshipTypes.length > 1) {
            console.warn(`节点 ${processNode.nodeName} 存在多种关系类型:`, relationshipTypes);
          }
          if (calculationMethods.length > 1) {
            console.warn(`节点 ${processNode.nodeName} 存在多种时效计算方式:`, calculationMethods);
          }
          
          // 使用第一个匹配记录的关系类型和计算方式作为处理方式
          const primaryRelationshipType = matchedCandidates[0].relationshipType;
          const primaryCalculationMethod = matchedCandidates[0].calculationMethod;
          
          // 添加调试日志
          console.log(`节点 ${processNode.nodeName} 调试信息:`);
          console.log('primaryCalculationMethod:', primaryCalculationMethod);
          console.log('primaryRelationshipType:', primaryRelationshipType);
          console.log('所有关系类型:', relationshipTypes);
          console.log('所有计算方式:', calculationMethods);
          
          let finalTimelineValue = 0;
          
          // 使用关系字段决定处理方式（累加值、最大值、默认）
          processingRule = primaryRelationshipType || '默认';
          
          console.log('processingRule:', processingRule);
          
          if (processingRule === '累加值') {
            finalTimelineValue = matchedCandidates.reduce((sum, candidate) => sum + candidate.timelineValue, 0);
            const totalOriginalHours = matchedCandidates.reduce((sum, candidate) => sum + candidate.originalHours, 0);
            
            console.log(`节点 ${processNode.nodeName} 累加值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`累加结果: 总计${totalOriginalHours}小时 → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          } else if (processingRule === '最大值') {
            finalTimelineValue = Math.max(...matchedCandidates.map(c => c.timelineValue));
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            
            console.log(`节点 ${processNode.nodeName} 最大值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`最大值结果: ${maxCandidate?.originalHours}小时(${maxCandidate?.calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = maxCandidate?.record || matchedCandidates[0].record;
          } else {
            finalTimelineValue = matchedCandidates[0].timelineValue;
            
            console.log(`节点 ${processNode.nodeName} 默认处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`默认结果: 使用第一条记录 ${matchedCandidates[0].originalHours}小时(${matchedCandidates[0].calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          }
          
          timelineValue = finalTimelineValue;
          // matchedTimelineRecord 已在上面的处理逻辑中设置
        }
        

        
        // 计算当前节点的开始和完成时间（使用工作日计算）
        const calculateTimeline = (startDate: Date, timelineValue: number, calculationMethod: string = '外部') => {
          // 根据计算方式调整开始时间
          const adjustedStartDate = adjustToNextWorkingHour(startDate, calculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          
          let endDate: Date;
          if (calculationMethod === '内部') {
            // 使用内部工作时间计算
            endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            // 使用原有的24小时制计算
            endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
          
          return {
          startDate: formatDate(adjustedStartDate, 'STORAGE_FORMAT'),
          endDate: formatDate(endDate, 'STORAGE_FORMAT')
        };
        };
        
        let nodeStartTime = new Date(cumulativeStartTime);
        
        // 应用起始日期调整规则
        if (processNode.startDateRule) {
          let ruleJson = '';
          if (typeof processNode.startDateRule === 'string') {
            ruleJson = processNode.startDateRule;
          } else if (processNode.startDateRule && processNode.startDateRule.text) {
            ruleJson = processNode.startDateRule.text;
          }
          
          if (ruleJson.trim()) {
            nodeStartTime = adjustStartDateByRule(nodeStartTime, ruleJson);
            console.log(`节点 ${processNode.nodeName} 应用起始日期调整规则后的开始时间:`, formatDate(nodeStartTime));
          }
        }
        
        // 应用JSON格式日期调整规则
        let ruleDescription = '';
        if (processNode.dateAdjustmentRule) {
          console.log('原始dateAdjustmentRule:', processNode.dateAdjustmentRule);
          let ruleText = '';
          if (typeof processNode.dateAdjustmentRule === 'string') {
            ruleText = processNode.dateAdjustmentRule;
          } else if (Array.isArray(processNode.dateAdjustmentRule)) {
            // 处理富文本数组格式
            ruleText = processNode.dateAdjustmentRule
              .filter(item => item.type === 'text')
              .map(item => item.text)
              .join('');
          } else if (processNode.dateAdjustmentRule && processNode.dateAdjustmentRule.text) {
            ruleText = processNode.dateAdjustmentRule.text;
          }
          
          console.log('解析后的ruleText:', ruleText);
          console.log('调整前的nodeStartTime:', formatDate(nodeStartTime));
          
          if (ruleText && ruleText.trim() !== '') {
            const result = adjustStartDateByJsonRule(nodeStartTime, ruleText);
            nodeStartTime = result.adjustedDate;
            ruleDescription = result.description || '';
            console.log(`节点 ${processNode.nodeName} 应用JSON日期调整规则后的开始时间:`, formatDate(nodeStartTime));
          }
        }
        
        // 获取当前节点的计算方式
        let nodeCalculationMethod = '外部'; // 默认值
        if (matchedCandidates.length > 0) {
          nodeCalculationMethod = matchedCandidates[0].calculationMethod;
        } else if (matchedTimelineRecord) {
          const calculationMethodField = matchedTimelineRecord.fields[calculationMethodFieldId];
          if (calculationMethodField) {
            if (typeof calculationMethodField === 'string') {
              nodeCalculationMethod = calculationMethodField;
            } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
              nodeCalculationMethod = calculationMethodField.text;
            }
          }
        }
        
        const timelineResult = timelineValue ? 
          calculateTimeline(nodeStartTime, timelineValue, nodeCalculationMethod) : 
          {
            startDate: formatDate(nodeStartTime, 'STORAGE_FORMAT'),
            endDate: '未找到时效数据'
          };
        
        let nodeEndTime: Date;
        if (timelineValue) {
          const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          if (nodeCalculationMethod === '内部') {
            nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
        } else {
          nodeEndTime = new Date(nodeStartTime);
        }
        
        // 计算跳过的天数
        const skippedWeekends = calculateSkippedWeekends(nodeStartTime, nodeEndTime, processNode.weekendDays);
        const actualDays = calculateActualDays(timelineResult.startDate, timelineResult.endDate);
        
        // 计算时间范围内实际跳过的自定义日期
        const excludedDatesInRange = calculateExcludedDatesInRange(nodeStartTime, nodeEndTime, processNode.excludedDates || []);
        
        results.push({
          processOrder: processNode.processOrder,
          nodeName: processNode.nodeName,
          matchedLabels: processNode.matchedLabels,
          timelineValue: timelineValue,
          estimatedStart: timelineResult.startDate,
          estimatedEnd: timelineResult.endDate,
          timelineRecordId: matchedTimelineRecord ? 
            (matchedTimelineRecord.id || matchedTimelineRecord.recordId || matchedTimelineRecord._id || matchedTimelineRecord.record_id) : null,
          // 新增：保存所有匹配记录的信息（用于累加情况）
          allMatchedRecords: matchedCandidates.length > 1 ? matchedCandidates.map(candidate => ({
            recordId: candidate.record.id || candidate.record.recordId || candidate.record._id || candidate.record.record_id,
            timelineValue: candidate.timelineValue,
            originalHours: candidate.originalHours,
            calculationMethod: candidate.calculationMethod,
            relationshipType: candidate.relationshipType
          })) : null,
          // 新增：标识是否为累加处理
          isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1,
          weekendDaysConfig: processNode.weekendDays, // 新增：保存休息日配置用于显示
          excludedDates: processNode.excludedDates || [], // 新增：保存不参与计算日期用于显示与快照
          // 新增：保存时间范围内实际跳过的日期
          actualExcludedDates: excludedDatesInRange.dates,
          actualExcludedDatesCount: excludedDatesInRange.count,
          calculationMethod: nodeCalculationMethod, // 新增：保存计算方式
          ruleDescription: ruleDescription, // 新增：保存规则描述
          skippedWeekends: skippedWeekends,
          actualDays: actualDays,
          // 新增：保存调整规则用于重新计算
          startDateRule: processNode.startDateRule,
          dateAdjustmentRule: processNode.dateAdjustmentRule,
          adjustmentDescription: ruleDescription // 新增：保存调整规则描述
        });
        
        // 更新累积时间：当前节点的完成时间成为下一个节点的开始时间
        if (timelineValue) {
          cumulativeStartTime = new Date(nodeEndTime);
        }
        
        console.log(`节点 ${processNode.nodeName} (顺序: ${processNode.processOrder}):`, {
          开始时间: formatDate(nodeStartTime),
          完成时间: formatDate(nodeEndTime),
          时效天数: timelineValue,
          计算方式: nodeCalculationMethod
        });
      }
      
      setTimelineResults(results);
      if (showUI) {
        setTimelineVisible(true);
      }
      
      console.log('按流程顺序计算的时效结果:', results);
      
      return results; // 返回计算结果
      
    } catch (error) {
      console.error('计算时效失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '计算时效失败，请检查表格配置'
        });
      }
      throw error; // 重新抛出错误
    } finally {
      setTimelineLoading(false);
    }
  };
  
  // 复合调整处理函数：根据缓冲期和交期余量状态决定调整方式
  const handleComplexAdjustment = (nodeIndex: number, adjustment: number) => {
    // 计算当前状态
    const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
    const baseBuferDays = baseBufferDays;
    
    // 智能缓冲期计算逻辑
    let dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
    
    // 只有在缓冲期为0时才检查最终限制：最后节点预计完成时间是否已达到客户期望日期
    let hasReachedFinalLimit = false;
    if (dynamicBufferDays === 0 && expectedDate && timelineResults.length > 0) {
      // 获取有效的最后流程完成日期
      let effectiveLastProcess = null;
      let lastCompletionDate = null;
      
      for (let i = timelineResults.length - 1; i >= 0; i--) {
        const process = timelineResults[i];
        const processDate = new Date(process.estimatedEnd);
        
        if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
          effectiveLastProcess = process;
          lastCompletionDate = processDate;
          break;
        }
      }
      
      if (!effectiveLastProcess) {
        effectiveLastProcess = timelineResults[timelineResults.length - 1];
        lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
      }
      
      // 计算最后流程完成日期（包含调整）
      const adjustedCompletionDate = new Date(lastCompletionDate);
      adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
      
      // 检查是否已达到客户期望日期
      const timeDiffToExpected = expectedDate.getTime() - adjustedCompletionDate.getTime();
      const daysToExpected = Math.ceil(timeDiffToExpected / (1000 * 60 * 60 * 24));
      hasReachedFinalLimit = daysToExpected <= 0;
    }
    
    // 如果已达到最终限制且是正向调整，则禁止操作
    if (hasReachedFinalLimit && adjustment > 0) {
      return;
    }
    
    // 调整逻辑：
    // 1. 优先使用缓冲期
    // 2. 缓冲期为0时，通过调整节点时效值实现连锁传递
    if (adjustment > 0) {
      // 正数调整：需要扣减
      if (dynamicBufferDays > 0) {
        // 1. 缓冲期 > 0，优先扣减缓冲期（通过调整节点时间）
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      } else {
        // 2. 缓冲期 = 0，通过调整节点时效值实现连锁传递
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      }
    } else if (adjustment < 0) {
      // 负数调整：需要恢复
      if (completionDateAdjustment > 0) {
        // 1. 优先恢复最后流程完成日期的调整
        const restoreAmount = Math.min(-adjustment, completionDateAdjustment);
        setCompletionDateAdjustment(completionDateAdjustment - restoreAmount);
        const remainingRestore = -adjustment - restoreAmount;
        
        if (remainingRestore > 0) {
          // 2. 如果还有剩余恢复量，恢复缓冲期（通过调整节点时间）
          const updatedResults = handleTimelineAdjustment(nodeIndex, -remainingRestore);
          // 如果调整失败，不进行后续操作
          if (!updatedResults) return;
        }
      } else if (totalAdjustments > 0) {
        // 直接恢复缓冲期
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      }
    }
  };
  
  // 调整时效值的函数
  const handleTimelineAdjustment = (nodeIndex: number, adjustment: number) => {
    const newAdjustments = { ...timelineAdjustments };
    const currentAdjustment = newAdjustments[nodeIndex] || 0;
    const newAdjustment = currentAdjustment + adjustment;
    
    // 防止调整后的时效值小于0（优先使用原始时效值，其次使用上次重算后的值）
    const baseValue = (typeof timelineResults[nodeIndex]?.timelineValue === 'number')
      ? timelineResults[nodeIndex]!.timelineValue
      : (typeof timelineResults[nodeIndex]?.adjustedTimelineValue === 'number')
        ? timelineResults[nodeIndex]!.adjustedTimelineValue
        : 0;
    if (baseValue + newAdjustment < 0) {
      return null;
    }
    
    // 检查当前调整的节点是否为周转周期节点
    const currentNodeName = timelineResults[nodeIndex]?.nodeName;
    const isTurnoverNode = currentNodeName === '周转周期';
    
    // 如果调整的是周转周期节点，直接返回（禁用手动调整）
    if (isTurnoverNode) {
      return null;
    }
    
    newAdjustments[nodeIndex] = newAdjustment;
    
    // 查找周转周期节点的索引
    const turnoverNodeIndex = timelineResults.findIndex(result => result.nodeName === '周转周期');
    
    // 如果存在周转周期节点，进行反向调整
    if (turnoverNodeIndex !== -1 && turnoverNodeIndex !== nodeIndex) {
      const turnoverCurrentAdjustment = newAdjustments[turnoverNodeIndex] || 0;
      const turnoverBaseValue = (typeof timelineResults[turnoverNodeIndex]?.timelineValue === 'number')
        ? timelineResults[turnoverNodeIndex]!.timelineValue
        : (typeof timelineResults[turnoverNodeIndex]?.adjustedTimelineValue === 'number')
          ? timelineResults[turnoverNodeIndex]!.adjustedTimelineValue
          : 0;
      
      // 计算周转周期的反向调整值
      const turnoverNewAdjustment = turnoverCurrentAdjustment - adjustment;
      
      // 确保周转周期调整后的值不小于0
      if (turnoverBaseValue + turnoverNewAdjustment >= 0) {
        newAdjustments[turnoverNodeIndex] = turnoverNewAdjustment;
      }
    }
    
    setTimelineAdjustments(newAdjustments);
    
    // 使用智能重算逻辑，只重算被调整的节点及其后续节点
    recalculateTimeline(newAdjustments);
    return timelineResults;
  };

  // 获取重新计算后的时间线结果（不更新状态）
  const getRecalculatedTimeline = (adjustments: {[key: number]: number}) => {
    const updatedResults = [...timelineResults];
    let cumulativeStartTime = startTime ? new Date(startTime) : new Date(); // 从起始时间开始
    
    for (let i = 0; i < updatedResults.length; i++) {
      const result = updatedResults[i];
      const baseTimelineValue = (typeof result.timelineValue === 'number')
        ? result.timelineValue
        : (typeof result.adjustedTimelineValue === 'number')
          ? result.adjustedTimelineValue
          : 0;
      const adjustment = adjustments[i] || 0;
      const adjustedTimelineValue = baseTimelineValue + adjustment;
      
      // 计算当前节点的开始时间
      let nodeStartTime = new Date(cumulativeStartTime);
      
      // 获取节点的计算方式、周末天数和排除日期
      const nodeCalculationMethod = result.calculationMethod || 'external';
      const nodeWeekendDays = result.weekendDays || [];
      const nodeExcludedDates = result.excludedDates || [];
      
      // 获取调整规则描述
      const ruleDescription = result.ruleDescription || '';
      
      // 计算节点的结束时间
      let nodeEndTime;
      if (adjustedTimelineValue > 0) {
        const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
        if (nodeCalculationMethod === 'internal') {
          nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        } else {
          nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        }
      } else {
        nodeEndTime = new Date(nodeStartTime);
      }
      
      // 计算跳过的天数
      const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates) : nodeStartTime;
      const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays);
      const estimatedStartStr = formatDate(adjustedStartTime);
      const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
      const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
      
      // 计算时间范围内实际跳过的自定义日期
      const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
      
      // 更新结果
      updatedResults[i] = {
        ...result,
        adjustedTimelineValue: adjustedTimelineValue,
        estimatedStart: estimatedStartStr,
        estimatedEnd: estimatedEndStr,
        adjustment: adjustment,
        calculationMethod: nodeCalculationMethod, // 保持计算方式
        skippedWeekends: skippedWeekends,
        actualDays: actualDays,
        // 更新时间范围内实际跳过的日期
        actualExcludedDates: excludedDatesInRange.dates,
        actualExcludedDatesCount: excludedDatesInRange.count,
        adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
        ruleDescription: ruleDescription // 添加更新后的规则描述
      };
      
      // 更新累积时间：当前节点的完成时间成为下一个节点的开始时间
      if (adjustedTimelineValue > 0) {
        cumulativeStartTime = new Date(nodeEndTime);
      }
    }
    
    return updatedResults;
  };

  // 重新计算时间线的函数
  const recalculateTimeline = (adjustments: {[key: number]: number}, forceRecalculateAll: boolean = false) => {
    const updatedResults = [...timelineResults];
    
    // 找到第一个被调整的节点索引
    const adjustedIndices = Object.keys(adjustments).map(k => parseInt(k)).filter(i => adjustments[i] !== 0);
    
    // 找到有实际完成时间的节点
    const actualCompletionIndices = Object.keys(actualCompletionDates)
      .map(k => parseInt(k))
      .filter(i => actualCompletionDates[i] !== null && actualCompletionDates[i] !== undefined);
    
    // 如果没有调整且不是强制重算，但有实际完成时间，需要重新计算
    if (adjustedIndices.length === 0 && !forceRecalculateAll && actualCompletionIndices.length === 0) {
      return; // 没有调整也没有实际完成时间，直接返回
    }
    
    // 确定第一个需要重新计算的节点索引
    let firstAdjustedIndex: number;
    
    if (forceRecalculateAll) {
      firstAdjustedIndex = 0;
    } else if (actualCompletionIndices.length > 0) {
      // 如果有实际完成时间，从最早有实际完成时间的节点的下一个节点开始重新计算
      const earliestActualCompletionIndex = Math.min(...actualCompletionIndices);
      const earliestAdjustmentIndex = adjustedIndices.length > 0 ? Math.min(...adjustedIndices) : Infinity;
      firstAdjustedIndex = Math.min(earliestActualCompletionIndex + 1, earliestAdjustmentIndex);
      console.log(`检测到实际完成时间，从节点 ${firstAdjustedIndex} 开始重新计算`);
    } else {
      firstAdjustedIndex = adjustedIndices.length > 0 ? Math.min(...adjustedIndices) : 0;
    }
    
    // 确保索引不超出范围
    firstAdjustedIndex = Math.max(0, Math.min(firstAdjustedIndex, updatedResults.length - 1));
    
    // 确定累积开始时间
    let cumulativeStartTime: Date;
    if (firstAdjustedIndex === 0) {
      // 如果调整的是第一个节点，从起始时间开始
      cumulativeStartTime = startTime ? new Date(startTime) : new Date();
    } else {
      // 如果调整的不是第一个节点，从前一个节点的结束时间开始
      const previousResult = updatedResults[firstAdjustedIndex - 1];
      const previousIndex = firstAdjustedIndex - 1;
      
      // 检查前一个节点是否有实际完成时间
      if (actualCompletionDates[previousIndex]) {
        // 使用实际完成时间作为下一个节点的开始时间
        cumulativeStartTime = new Date(actualCompletionDates[previousIndex]!);
        console.log(`节点 ${previousIndex} 使用实际完成时间: ${formatDate(cumulativeStartTime)}`);
      } else {
        // 使用预计完成时间
        cumulativeStartTime = new Date(previousResult.estimatedEnd);
      }
    }
    
    // 只重新计算从第一个调整节点开始的后续节点
    for (let i = firstAdjustedIndex; i < updatedResults.length; i++) {
      const result = updatedResults[i];
      const baseTimelineValue = (typeof result.timelineValue === 'number')
        ? result.timelineValue
        : (typeof result.adjustedTimelineValue === 'number')
          ? result.adjustedTimelineValue
          : 0;
      const adjustment = adjustments[i] || 0;
      const adjustedTimelineValue = baseTimelineValue + adjustment;
      
      // 计算当前节点的开始时间
      let nodeStartTime = new Date(cumulativeStartTime);
      
      // 重新应用起始日期调整规则
      if (result.startDateRule) {
        let ruleJson = '';
        if (typeof result.startDateRule === 'string') {
          ruleJson = result.startDateRule;
        } else if (result.startDateRule && result.startDateRule.text) {
          ruleJson = result.startDateRule.text;
        }
        
        if (ruleJson.trim()) {
          nodeStartTime = adjustStartDateByRule(nodeStartTime, ruleJson);
        }
      }
      
      // 重新应用JSON格式日期调整规则
      let ruleDescription = result.ruleDescription; // 保持原有描述作为默认值
      if (result.dateAdjustmentRule) {
        let ruleText = '';
        if (typeof result.dateAdjustmentRule === 'string') {
          ruleText = result.dateAdjustmentRule;
        } else if (Array.isArray(result.dateAdjustmentRule)) {
          ruleText = result.dateAdjustmentRule
            .filter(item => item.type === 'text')
            .map(item => item.text)
            .join('');
        } else if (result.dateAdjustmentRule && result.dateAdjustmentRule.text) {
          ruleText = result.dateAdjustmentRule.text;
        }
        
        if (ruleText && ruleText.trim() !== '') {
          const adjustmentResult = adjustStartDateByJsonRule(nodeStartTime, ruleText);
          nodeStartTime = adjustmentResult.adjustedDate;
          // 更新规则描述
          if (adjustmentResult.description) {
            ruleDescription = adjustmentResult.description;
          }
        }
      }
      
      const nodeWeekendDays = result.weekendDaysConfig || []; // 使用节点特定的休息日配置
      const nodeCalculationMethod = result.calculationMethod || '外部'; // 获取节点的计算方式
      
      let nodeEndTime: Date;
      const nodeExcludedDates = Array.isArray(result.excludedDates) ? result.excludedDates : [];
      if (adjustedTimelineValue > 0) {
        const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
        if (nodeCalculationMethod === '内部') {
          nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        } else {
          nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        }
      } else {
        nodeEndTime = new Date(nodeStartTime);
      }
      
      // 计算跳过的天数
      const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates) : nodeStartTime;
      const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays);
      const estimatedStartStr = formatDate(adjustedStartTime);
      const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
      const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
      
      // 计算时间范围内实际跳过的自定义日期
      const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
      
      // 更新结果
        updatedResults[i] = {
          ...result,
          adjustedTimelineValue: adjustedTimelineValue,
          estimatedStart: estimatedStartStr,
          estimatedEnd: estimatedEndStr,
          adjustment: adjustment,
          calculationMethod: nodeCalculationMethod, // 保持计算方式
          skippedWeekends: skippedWeekends,
          actualDays: actualDays,
          // 更新时间范围内实际跳过的日期
          actualExcludedDates: excludedDatesInRange.dates,
          actualExcludedDatesCount: excludedDatesInRange.count,
          adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
          ruleDescription: ruleDescription // 添加更新后的规则描述
        };
      
      // 更新累积时间：优先使用当前节点的实际完成时间，否则使用预计完成时间
      if (adjustedTimelineValue > 0) {
        if (actualCompletionDates[i]) {
          // 如果当前节点有实际完成时间，使用实际完成时间
          cumulativeStartTime = new Date(actualCompletionDates[i]!);
        } else {
          // 否则使用预计完成时间
          cumulativeStartTime = new Date(nodeEndTime);
        }
      }
    }
    
    setTimelineResults(updatedResults);
  };

  // 添加快照还原状态标志
  const [isRestoringSnapshot, setIsRestoringSnapshot] = useState(false);

  // 当起始时间变更时，重新以最新起始时间为基准重算全流程
  useEffect(() => {
    if (timelineResults.length > 0 && !isRestoringSnapshot) {
      recalculateTimeline(timelineAdjustments, true); // 强制重算所有节点
    }
  }, [startTime, isRestoringSnapshot]);

  // 重置调整的函数
  const resetTimelineAdjustments = () => {
    setTimelineAdjustments({});
    setDeliveryMarginDeductions(0); // 同时重置交期余量扣减
    setCompletionDateAdjustment(0); // 重置最后流程完成日期调整
    setActualCompletionDates({}); // 重置实际完成日期
    recalculateTimeline({}, true); // 强制重算所有节点
  };
  
  // 已移除未使用的 getTimelineLabelFieldId 辅助函数

  // 写入货期记录表的函数
  const writeToDeliveryRecordTable = async (
    timelineResults: any[],
    processRecordIds: string[],
    timelineAdjustments: {[key: number]: number} = {},
    batchData?: {
      selectedRecords: string[],
      recordDetails: any[],
      labels?: Record<string, any>,
      expectedDate?: any,
      startTime?: any
    }
  ) => {
    try {
      console.log('=== 开始写入货期记录表 ===');
      console.log('当前模式:', mode);
      console.log('timelineResults数量:', timelineResults?.length || 0);
      console.log('processRecordIds数量:', processRecordIds?.length || 0);
      console.log('timelineAdjustments:', timelineAdjustments);
      console.log('timelineResults详情:', timelineResults);
      console.log('processRecordIds详情:', processRecordIds);
      
      // 获取货期记录表
      console.log('正在获取货期记录表...');
      const deliveryRecordTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
      console.log('成功获取货期记录表');
      
      // 检查字段是否存在
      console.log('正在检查和获取所有必需字段...');
      const fieldsToCheck = [
        DELIVERY_FOREIGN_ID_FIELD_ID,
        DELIVERY_LABELS_FIELD_ID,
        DELIVERY_STYLE_FIELD_ID,
        DELIVERY_COLOR_FIELD_ID,
        DELIVERY_CREATE_TIME_FIELD_ID,
        DELIVERY_EXPECTED_DATE_FIELD_ID,
        DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID,
        DELIVERY_NODE_DETAILS_FIELD_ID,
        DELIVERY_ADJUSTMENT_INFO_FIELD_ID,  // 添加货期调整信息字段
        DELIVERY_START_TIME_FIELD_ID        // 新增：起始时间字段
      ];
      console.log('需要检查的字段ID列表:', fieldsToCheck);
      
      // 获取各个字段
      console.log('正在获取各个字段对象...');
      const foreignIdField = await deliveryRecordTable.getField(DELIVERY_FOREIGN_ID_FIELD_ID);
      const labelsField = await deliveryRecordTable.getField(DELIVERY_LABELS_FIELD_ID);
      const styleField = await deliveryRecordTable.getField(DELIVERY_STYLE_FIELD_ID);
      const colorField = await deliveryRecordTable.getField(DELIVERY_COLOR_FIELD_ID);
      const text2Field = await deliveryRecordTable.getField(DELIVERY_TEXT2_FIELD_ID);
      const createTimeField = await deliveryRecordTable.getField(DELIVERY_CREATE_TIME_FIELD_ID);
      const expectedDateField = await deliveryRecordTable.getField(DELIVERY_EXPECTED_DATE_FIELD_ID);
      const nodeDetailsField = await deliveryRecordTable.getField(DELIVERY_NODE_DETAILS_FIELD_ID);
      const customerExpectedDateField = await deliveryRecordTable.getField(DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID);
      const adjustmentInfoField = await deliveryRecordTable.getField(DELIVERY_ADJUSTMENT_INFO_FIELD_ID);
      const versionField = await deliveryRecordTable.getField(DELIVERY_VERSION_FIELD_ID);
      const startTimeField = await deliveryRecordTable.getField(DELIVERY_START_TIME_FIELD_ID);
      const snapshotField = await deliveryRecordTable.getField(DELIVERY_SNAPSHOT_JSON_FIELD_ID);
      console.log('成功获取所有字段对象');
      
      // 检查标签汇总字段的类型
      console.log('标签汇总字段信息:', {
        id: labelsField.id,
        name: labelsField.name,
        type: labelsField.type,
        property: labelsField.property
      });
      
      // 获取foreign_id：调整模式严格使用快照数据，生成模式优先使用选择记录
      console.log('=== 开始获取foreign_id ===');
      let foreignId = '';
      
      // 使用传递的数据或全局状态
      const currentSelectedRecords = batchData?.selectedRecords || selectedRecords;
      const currentRecordDetails = batchData?.recordDetails || recordDetails;
      
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的foreign_id，即使为空也不回退
        foreignId = currentForeignId;
        console.log('调整模式：严格使用快照恢复的foreign_id:', foreignId);
      } else if (currentSelectedRecords.length > 0) {
        // 生成模式：从选择记录获取
        console.log('生成模式：从选择记录获取foreign_id');
        console.log('selectedRecords[0]:', currentSelectedRecords[0]);
        
        if (batchData) {
          // 批量模式：直接从传递的数据中获取
          const firstRecord = currentRecordDetails[0];
          if (firstRecord && firstRecord.fields && firstRecord.fields['fldpvBfeC0']) {
            const fieldValue = firstRecord.fields['fldpvBfeC0'];
            foreignId = extractText(fieldValue);
            console.log('批量模式：从传递数据获取foreign_id:', foreignId);
          }
        } else {
          // 生成模式：从数据库获取
          const table = await bitable.base.getTable(TABLE_ID);
          const firstRecord = await table.getRecordById(currentSelectedRecords[0]);
          console.log('获取到的记录:', firstRecord);
          const fieldValue = firstRecord.fields['fldpvBfeC0'];
          console.log('fldpvBfeC0字段值:', fieldValue);
          
          foreignId = extractText(fieldValue);
        }
      }
      
      // 生成模式的回退逻辑：记录详情
      if (mode !== 'adjust' && !foreignId && currentRecordDetails.length > 0) {
        const first = currentRecordDetails[0];
        const val = first.fields['fldpvBfeC0'];
        foreignId = extractText(val);
      }
      // 生成模式的最后回退：快照状态
      if (mode !== 'adjust' && !foreignId && currentForeignId) {
        foreignId = currentForeignId;
      }
      
      // 获取款式与颜色：调整模式优先使用快照数据，生成模式优先使用记录详情
      let style = '';
      let color = '';
      
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的数据，即使为空也不回退
        style = currentStyleText;
        color = currentColorText;
        console.log('调整模式：严格使用快照恢复的款式:', style, '颜色:', color);
      } else {
        // 生成模式：优先使用记录详情
        if (currentRecordDetails.length > 0) {
          const first = currentRecordDetails[0];
          style = extractText(first.fields['fld6Uw95kt']) || currentStyleText || '';
          color = extractText(first.fields['flde85ni4O']) || currentColorText || '';
        } else {
          // 回退：使用快照回填的状态
          style = currentStyleText || '';
          color = currentColorText || '';
          // 若仍为空且有选择记录，仅做一次读取
          if ((!style || !color) && currentSelectedRecords.length > 0) {
            const table = await bitable.base.getTable(TABLE_ID);
            const firstRecord = await table.getRecordById(currentSelectedRecords[0]);
            style = style || extractText(firstRecord.fields['fld6Uw95kt']);
            color = color || extractText(firstRecord.fields['flde85ni4O']);
          }
        }
      }
      
      // 获取文本2：调整模式优先使用快照数据；生成模式在批量模式下填写
      let text2 = '';
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的数据，即使为空也不回退
        text2 = currentText2; // 直接使用快照值，不使用 || '' 的回退逻辑
        console.log('调整模式：严格使用快照恢复的文本2:', text2);
      } else {
        if (batchData && currentRecordDetails.length > 0) {
          const first = currentRecordDetails[0];
          if (first?.fields?.['fldG6LZnmU']) {
            text2 = extractText(first.fields['fldG6LZnmU']);
          }
          // 兜底：若批量数据中显式传递了text2，则使用之
          if (!text2 && (batchData as any).text2) {
            try { text2 = extractText((batchData as any).text2); } catch { text2 = (batchData as any).text2; }
          }
          console.log('生成模式（批量）：文本2来自批量数据:', text2);
        } else {
          // 非批量的生成模式：保持为空
          text2 = '';
          console.log('生成模式：文本2字段保持为空');
        }
      }
      
      // 获取标签汇总：批量模式优先使用传入的labels
      const selectedLabelValues = batchData?.labels
        ? Object.values(batchData.labels).flat().filter(Boolean)
        : Object.values(selectedLabels).flat().filter(Boolean);
      
      // 获取预计交付日期（交期余量的日期版本：最后流程完成日期 + 基础缓冲期）
      let expectedDeliveryDate = null;
      if (timelineResults.length > 0) {
        // 从后往前查找第一个有效的流程完成日期（与交期余量计算逻辑一致）
        let effectiveLastProcess = null;
        for (let i = timelineResults.length - 1; i >= 0; i--) {
          const process = timelineResults[i];
          if (process.estimatedEnd && 
              !process.estimatedEnd.includes('未找到') && 
              !process.estimatedEnd.includes('时效值为0') &&
              process.estimatedEnd !== 'Invalid Date') {
            effectiveLastProcess = process;
            break;
          }
        }
        
        if (effectiveLastProcess) {
          try {
            const lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
            
            // 计算动态缓冲期：基础缓冲期 - 节点总调整量，最小为0天
            const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
            const baseBuferDays = baseBufferDays;
            const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
            
            // 加上动态缓冲期
            const deliveryDate = new Date(lastCompletionDate);
            deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
            expectedDeliveryDate = deliveryDate.getTime();
          } catch (error) {
            console.error('转换预计交付日期失败:', error);
          }
        }
      }
      
      // 获取客户期望日期：批量模式优先使用传入的expectedDate
      let customerExpectedDate = null;
      if (batchData?.expectedDate) {
        try {
          customerExpectedDate = new Date(batchData.expectedDate).getTime();
        } catch { /* 忽略转换错误，保持null */ }
      } else if (expectedDate) {
        customerExpectedDate = expectedDate.getTime(); // 转换为时间戳
      }
      
      // 创建当前时间戳
      const currentTime = new Date().getTime();
      
      // 计算版本号（数字）并格式化货期调整信息
      let versionNumber = 1;
      try {
        if (mode === 'adjust' && currentVersionNumber !== null) {
          // 调整模式：优先使用快照version +1
          versionNumber = currentVersionNumber + 1;
        } else if (foreignId) {
          const existing = await deliveryRecordTable.getRecords({
            pageSize: 5000,
            filter: {
              conjunction: 'and',
              conditions: [{
                fieldId: DELIVERY_FOREIGN_ID_FIELD_ID,
                operator: 'is',
                value: [foreignId]
              }]
            }
          });
          const count = existing.records?.length || 0;
          versionNumber = count + 1;
        }
      } catch (e) {
        console.warn('计算版本号失败:', e);
      }

      let adjustmentInfo = `版本：V${versionNumber}`;
      if (Object.keys(timelineAdjustments).length > 0) {
        const adjustmentTexts = Object.entries(timelineAdjustments).map(([nodeIndex, adjustment]) => {
          const nodeName = timelineResults[parseInt(nodeIndex)]?.nodeName || `节点${parseInt(nodeIndex) + 1}`;
          return `${nodeName}: ${adjustment > 0 ? '+' : ''}${adjustment.toFixed(1)} 天`;
        });
        adjustmentInfo += `\n当前调整：\n${adjustmentTexts.join('\n')}`;
      }
      
      // 在创建Cell之前进行数据校验（移除冗余日志）

      // ===== 构建完整快照（保持与流程数据表写入时的一致内容）并写入到货期记录表 =====
      const expectedDateTimestamp = (batchData?.expectedDate || expectedDate)
        ? (batchData?.expectedDate || expectedDate).getTime()
        : null;
      const expectedDateString = (batchData?.expectedDate || expectedDate)
        ? format((batchData?.expectedDate || expectedDate), DATE_FORMATS.STORAGE_FORMAT)
        : null;
      const currentStartTime = batchData?.startTime || startTime;
      const currentSelectedLabels = batchData?.labels || selectedLabels;

      // 与快照字段保持相同的命名
      const styleText = style || '';
      const colorText = color || '';

      const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);

      // 检查是否达到最终限制
      let hasReachedFinalLimit = false;
      const currentExpectedDate = batchData?.expectedDate || expectedDate;
      if (dynamicBufferDays === 0 && currentExpectedDate && timelineResults.length > 0) {
        const lastNode = timelineResults[timelineResults.length - 1];
        if (lastNode && lastNode.estimatedEnd && !lastNode.estimatedEnd.includes('未找到')) {
          try {
            const lastCompletionDate = new Date(lastNode.estimatedEnd);
            const daysToExpected = Math.ceil((currentExpectedDate.getTime() - lastCompletionDate.getTime()) / (1000 * 60 * 60 * 24));
            hasReachedFinalLimit = daysToExpected <= 0;
          } catch (error) {
            console.warn('计算最终限制状态失败:', error);
          }
        }
      }

      const globalSnapshot = {
        version: versionNumber,
        foreignId,
        styleText,
        colorText,
        text2,
        mode,
        selectedLabels: currentSelectedLabels,
        expectedDateTimestamp,
        expectedDateString,
        startTimestamp: currentStartTime ? currentStartTime.getTime() : undefined,
        startString: currentStartTime ? formatDate(currentStartTime, 'STORAGE_FORMAT') : undefined,
        timelineAdjustments,
        generationModeState: {
          currentForeignId,
          currentStyleText,
          currentColorText,
          currentText2,
          currentVersionNumber: versionNumber,
          recordDetails: recordDetails || [],
          hasSelectedLabels: Object.values(selectedLabels).some(value => {
            return Array.isArray(value) ? value.length > 0 : Boolean(value);
          }),
          labelSelectionComplete: Object.keys(selectedLabels).length > 0
        },
        bufferManagement: {
          baseDays: baseBuferDays,
          totalAdjustments,
          dynamicBufferDays,
          hasReachedFinalLimit
        },
        chainAdjustmentSystem: {
          enabled: true,
          lastCalculationTime: new Date().getTime(),
          adjustmentHistory: timelineAdjustments
        },
        timelineCalculationState: {
          calculationTimestamp: new Date().getTime(),
          totalNodes: timelineResults.length,
          hasValidResults: timelineResults.length > 0,
          lastCalculationMode: mode
        },
        totalNodes: timelineResults.length,
        isGlobalSnapshot: true
      };

      // 选择用于快照的最后一个有效节点（与流程写入时的节点快照结构一致）
      let selectedIndex = -1;
      for (let i = timelineResults.length - 1; i >= 0; i--) {
        const r = timelineResults[i];
        if (r.estimatedEnd && !r.estimatedEnd.includes('未找到') && r.estimatedEnd.trim() !== '') {
          selectedIndex = i;
          break;
        }
      }
      if (selectedIndex === -1) selectedIndex = 0; // 无有效结束时间时兜底为第一个

      const selectedResult = timelineResults[selectedIndex];
      let nodeStartTs = null as number | null;
      let nodeEndTs = null as number | null;
      if (selectedResult.estimatedStart && !selectedResult.estimatedStart.includes('未找到')) {
        try { nodeStartTs = new Date(selectedResult.estimatedStart).getTime(); } catch {}
      }
      if (selectedResult.estimatedEnd && !selectedResult.estimatedEnd.includes('未找到')) {
        try { nodeEndTs = new Date(selectedResult.estimatedEnd).getTime(); } catch {}
      }

      const nodeSnapshot = {
        processOrder: selectedResult.processOrder,
        nodeName: selectedResult.nodeName,
        matchedLabels: selectedResult.matchedLabels,
        timelineValue: selectedResult.timelineValue,
        estimatedStart: selectedResult.estimatedStart,
        estimatedEnd: selectedResult.estimatedEnd,
        estimatedStartTimestamp: nodeStartTs,
        estimatedEndTimestamp: nodeEndTs,
        timelineRecordId: selectedResult.timelineRecordId,
        allMatchedRecords: selectedResult.allMatchedRecords,
        isAccumulated: selectedResult.isAccumulated,
        weekendDaysConfig: selectedResult.weekendDaysConfig,
        excludedDates: selectedResult.excludedDates,
        actualExcludedDates: selectedResult.actualExcludedDates,
        actualExcludedDatesCount: selectedResult.actualExcludedDatesCount,
        calculationMethod: selectedResult.calculationMethod,
        ruleDescription: selectedResult.ruleDescription,
        skippedWeekends: selectedResult.skippedWeekends,
        actualDays: selectedResult.actualDays,
        adjustedTimelineValue: selectedResult.adjustedTimelineValue,
        adjustment: selectedResult.adjustment,
        adjustmentDescription: selectedResult.adjustmentDescription,
        startDateRule: selectedResult.startDateRule,
        dateAdjustmentRule: selectedResult.dateAdjustmentRule,
        nodeCalculationState: {
          hasValidTimelineValue: selectedResult.timelineValue > 0,
          hasValidStartTime: Boolean(nodeStartTs),
          hasValidEndTime: Boolean(nodeEndTs),
          calculationTimestamp: new Date().getTime(),
          originalTimelineValue: selectedResult.timelineValue,
          finalAdjustedValue: selectedResult.adjustedTimelineValue || selectedResult.timelineValue
        },
        chainAdjustmentNode: {
          nodeIndex: selectedIndex,
          hasAdjustment: selectedResult.adjustment !== undefined && selectedResult.adjustment !== 0,
          adjustmentValue: selectedResult.adjustment || 0,
          isChainSource: selectedResult.adjustment !== undefined && selectedResult.adjustment !== 0,
          affectedByChain: selectedIndex > 0
        },
        isNodeSnapshot: true
      };

      const completeSnapshot = {
        ...globalSnapshot,
        ...nodeSnapshot,
        timelineResults: timelineResults,
        currentNodeIndex: selectedIndex,
        currentNodeName: selectedResult.nodeName,
        isCompleteSnapshot: true,
        snapshotType: 'complete'
      };
      const snapshotJson = JSON.stringify(completeSnapshot);

      // 使用createCell方法创建各个字段的Cell
      const foreignIdCell = await foreignIdField.createCell(foreignId);
      const labelsCell = selectedLabelValues.length > 0 ? await labelsField.createCell(selectedLabelValues) : null;
      const styleCell = await styleField.createCell(style);
      const colorCell = await colorField.createCell(color);
      const text2Cell = await text2Field.createCell(text2);
      const createTimeCell = await createTimeField.createCell(currentTime);
      
      // 调试日志：检查startTime参数
      console.log('批量模式 - startTime参数:', startTime);
      console.log('批量模式 - startTime类型:', typeof startTime);
      console.log('批量模式 - currentTime:', currentTime, '对应日期:', new Date(currentTime).toLocaleString());
      
      const startTimestamp = batchData?.startTime
        ? new Date(batchData.startTime).getTime()
        : (startTime ? startTime.getTime() : currentTime);
      console.log('批量模式 - 最终使用的startTimestamp:', startTimestamp, '对应日期:', new Date(startTimestamp).toLocaleString());
      
      const startTimeCell = await startTimeField.createCell(startTimestamp);
      const snapshotCell = await snapshotField.createCell(snapshotJson);
      const expectedDateCell = expectedDeliveryDate ? await expectedDateField.createCell(expectedDeliveryDate) : null;
      const customerExpectedDateCell = customerExpectedDate ? await customerExpectedDateField.createCell(customerExpectedDate) : null;
      // 对于关联记录字段，确保传入的是记录ID数组
      const nodeDetailsCell = processRecordIds.length > 0 ? 
        await nodeDetailsField.createCell({ recordIds: processRecordIds }) : null;
      // 创建货期调整信息Cell
      const adjustmentInfoCell = adjustmentInfo ? await adjustmentInfoField.createCell(adjustmentInfo) : null;
      // 创建版本号Cell（数字）
      const versionCell = await versionField.createCell(versionNumber);
      
      // 组合所有Cell到一个记录中
      const recordCells = [foreignIdCell, styleCell, colorCell, text2Cell, createTimeCell, startTimeCell, versionCell, snapshotCell];
      
      // 只有当数据存在时才添加对应的Cell
      if (labelsCell) recordCells.push(labelsCell);
      if (expectedDateCell) recordCells.push(expectedDateCell);
      if (customerExpectedDateCell) recordCells.push(customerExpectedDateCell);
      if (nodeDetailsCell) recordCells.push(nodeDetailsCell);
      if (adjustmentInfoCell) recordCells.push(adjustmentInfoCell);
      
      // 添加记录到货期记录表
      const addedRecord = await deliveryRecordTable.addRecord(recordCells);
      
      return addedRecord;
    } catch (error) {
      console.error('写入货期记录表详细错误:', {
        error: error,
        message: error.message,
        stack: error.stack,
        recordCellsLength: typeof recordCells !== 'undefined' ? recordCells.length : 'recordCells未定义'
      });
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '写入货期记录表失败: ' + (error as Error).message
        });
      }
      throw error;
    }
  };

  // 写入流程数据表的函数
  const writeToProcessDataTable = async (timelineResults: any[], batchData?: {
    selectedRecords: string[], 
    recordDetails: any[], 
    labels?: Record<string, any>, 
    expectedDate?: any, 
    startTime?: any
  }): Promise<string[]> => {
    try {
      console.log('=== 开始写入流程数据表 ===');
      console.log('当前模式:', mode);
      console.log('timelineResults数量:', timelineResults?.length || 0);
      console.log('timelineResults详情:', timelineResults);
      
      // 获取流程数据表和流程配置表
      console.log('正在获取流程数据表和流程配置表...');
      const processDataTable = await bitable.base.getTable(PROCESS_DATA_TABLE_ID);
      const processConfigTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      console.log('成功获取数据表');
      
      // 获取所有需要的字段
      console.log('正在获取所有必需字段...');
      const foreignIdField = await processDataTable.getField(FOREIGN_ID_FIELD_ID);
      const processNameField = await processDataTable.getField(PROCESS_NAME_FIELD_ID);
      const processOrderField = await processDataTable.getField(PROCESS_ORDER_FIELD_ID_DATA);
      const startDateField = await processDataTable.getField(ESTIMATED_START_DATE_FIELD_ID);
      const endDateField = await processDataTable.getField(ESTIMATED_END_DATE_FIELD_ID);
      const versionField = await processDataTable.getField(PROCESS_VERSION_FIELD_ID);
      const timelinessField = await processDataTable.getField(PROCESS_TIMELINESS_FIELD_ID);
      console.log('成功获取所有字段');
      
      // 获取foreign_id - 支持批量模式直接传递数据
      console.log('=== 开始获取foreign_id ===');
      let foreignId = null;
      
      // 使用传递的数据或全局状态
      const currentSelectedRecords = batchData?.selectedRecords || selectedRecords;
      const currentRecordDetails = batchData?.recordDetails || recordDetails;
      
      console.log('selectedRecords数量:', currentSelectedRecords?.length || 0);
      console.log('recordDetails数量:', currentRecordDetails?.length || 0);
      console.log('selectedRecords:', currentSelectedRecords);
      console.log('recordDetails:', currentRecordDetails);
      
      if (currentSelectedRecords.length > 0 && currentRecordDetails.length > 0) {
        // 从第一个选择的记录的详情中获取fldpvBfeC0字段的值
        const firstRecord = currentRecordDetails[0];
        if (firstRecord && firstRecord.fields && firstRecord.fields['fldpvBfeC0']) {
          const fieldValue = firstRecord.fields['fldpvBfeC0'];
          foreignId = extractText(fieldValue);
          console.log('从fldpvBfeC0字段获取到的foreign_id:', foreignId);
        } else {
          console.warn('未在记录详情中找到fldpvBfeC0字段');
          console.log('第一个记录的字段:', firstRecord?.fields);
        }
      }
      
      // 快照回填：在调整模式通过快照还原时使用当前foreign_id状态
      if (!foreignId && currentForeignId) {
        foreignId = currentForeignId;
        console.log('使用快照恢复的foreign_id:', foreignId);
      }
      
      if (!foreignId) {
        console.warn('未找到foreign_id，跳过写入流程数据表');
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '未找到foreign_id字段，无法写入流程数据表'
          });
        }
        return [];
      }
      
      // 先删除该foreign_id的所有现有记录
      console.log('=== 开始删除现有记录 ===');
      console.log('使用的foreign_id:', foreignId);
      try {
        console.log('正在查询现有记录...');
        const existingRecords = await processDataTable.getRecords({
          pageSize: 5000,
          filter: {
            conjunction: 'And',
            conditions: [{
              fieldId: FOREIGN_ID_FIELD_ID,
              operator: 'is',
              value: [actualForeignId]
            }]
          }
        });
        
        console.log('查询到现有记录数量:', existingRecords.records?.length || 0);
        
        if (existingRecords.records && existingRecords.records.length > 0) {
          const recordIdsToDelete = existingRecords.records.map(record => record.id);
          console.log('准备删除的记录ID:', recordIdsToDelete);
          await processDataTable.deleteRecords(recordIdsToDelete);
          console.log(`成功删除 ${recordIdsToDelete.length} 条现有记录`);
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'info',
              message: `已删除 ${recordIdsToDelete.length} 条现有流程数据`
            });
          }
        } else {
          console.log('没有找到需要删除的现有记录');
        }
      } catch (deleteError) {
        console.error('删除现有记录时出错:', deleteError);
        // 继续执行，不中断流程
      }
      
      // 构建页面快照JSON（确保可一模一样还原）
      // 计算版本号：数字。默认按 foreign_id 在货期记录表的记录数量 + 1
      let versionNumber = 1;
      try {
        const deliveryRecordTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
        if (mode === 'adjust' && currentVersionNumber !== null) {
          // 调整模式：优先使用快照version +1，避免公式字段读取错误
          versionNumber = currentVersionNumber + 1;
        } else if (foreignId) {
          const existing = await deliveryRecordTable.getRecords({
            pageSize: 5000,
            filter: {
              conjunction: 'and',
              conditions: [{
                fieldId: DELIVERY_FOREIGN_ID_FIELD_ID,
                operator: 'is',
                value: [foreignId]
              }]
            }
          });
          const count = existing.records?.length || 0;
          versionNumber = count + 1;
        }
      } catch (e) {
        console.warn('计算版本号失败:', e);
      }


      // 使用createCell方法准备要写入的记录数据
        const recordCellsToAdd = [];
        
        for (let index = 0; index < timelineResults.length; index++) {
          const result = timelineResults[index];
          console.log('处理节点数据:', result);
          
          // 检查是否有有效的预计完成时间（只检查结束时间）
          const hasValidEndTime = (
            result.estimatedEnd && 
            !result.estimatedEnd.includes('未找到') && 
            result.estimatedEnd.trim() !== ''
          );
          
          // 如果没有有效的预计完成时间，跳过这个节点
          if (!hasValidEndTime) {
            console.log(`跳过节点 "${result.nodeName}" - 未找到有效的预计完成时间`);
            continue;
          }
          
          // 转换日期格式为时间戳（毫秒）
          let startTimestamp = null;
          let endTimestamp = null;
          
          if (result.estimatedStart && !result.estimatedStart.includes('未找到')) {
            try {
              startTimestamp = new Date(result.estimatedStart).getTime();
            } catch (error) {
              console.error(`转换开始时间失败:`, error);
            }
          }
          
          if (result.estimatedEnd && !result.estimatedEnd.includes('未找到')) {
            try {
              endTimestamp = new Date(result.estimatedEnd).getTime();
            } catch (error) {
              console.error(`转换结束时间失败:`, error);
            }
          }
          
          
          // 使用createCell方法创建每个字段的Cell
          const foreignIdCell = await foreignIdField.createCell(foreignId);
          // 直接使用节点名称创建单元格
          const processNameCell = await processNameField.createCell(result.nodeName);
          const processOrderCell = await processOrderField.createCell(result.processOrder);
          const startDateCell = startTimestamp ? await startDateField.createCell(startTimestamp) : null;
          const endDateCell = endTimestamp ? await endDateField.createCell(endTimestamp) : null;
          
          // 组合所有Cell到一个记录中
          const versionCell = await versionField.createCell(versionNumber);
          const timelinessCell = (typeof result.timelineValue === 'number')
            ? await timelinessField.createCell(result.timelineValue)
            : null;
          const recordCells = [
            foreignIdCell,
            processNameCell,
            processOrderCell,
            versionCell
          ];
          
          // 只有当时间戳存在时才添加日期Cell
          if (startDateCell) recordCells.push(startDateCell);
          if (endDateCell) recordCells.push(endDateCell);
          if (timelinessCell) recordCells.push(timelinessCell);
          
          console.log(`准备写入的Cell记录 - ${result.nodeName}:`, recordCells);
          recordCellsToAdd.push(recordCells);
        }
      
      console.log('所有准备写入的Cell记录:', recordCellsToAdd);
      
      // 在添加记录的部分，收集记录ID
      const addedRecordIds: string[] = [];
      
      if (recordCellsToAdd.length > 0) {
        try {
          // 使用addRecords进行批量写入
          const addedRecords = await processDataTable.addRecords(recordCellsToAdd);
          // 直接使用返回值，不需要map操作
          addedRecordIds.push(...addedRecords);
          console.log(`批量写入成功，记录ID:`, addedRecords);
        } catch (error) {
          console.error('批量写入失败，尝试逐条写入:', error);
          // 如果批量写入失败，回退到逐条写入
          for (const recordCells of recordCellsToAdd) {
            const addedRecord = await processDataTable.addRecord(recordCells);
            addedRecordIds.push(addedRecord);
            console.log('成功添加记录:', addedRecord);
          }
        }
        
        console.log(`成功写入 ${addedRecordIds.length} 条流程数据`);
        
        // 显示成功提示
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'success',
            message: `成功写入 ${addedRecordIds.length} 条流程数据到流程数据表`
          });
        }
        
        return addedRecordIds; // 返回记录ID列表
      } else {
        console.warn('没有有效的记录可以写入');
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '没有有效的流程数据可以写入 - 所有节点都缺少时效数据'
          });
        }
        return [];
      }
      
    } catch (error) {
      console.error('写入流程数据表失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `写入流程数据表失败: ${(error as Error).message}`
        });
      }
      return [];
    }
  };

  // 批量处理函数
  // 批量模式：模拟生成模式的操作（简化版本）
  const simulateGenerationModeForBatch = async (
    recordId: string,
    extractedLabels: {[key: string]: string | string[]},
    extractedStartTime: Date | null,
    extractedExpectedDate: Date | null,
    style: any,
    color: any,
    foreignId: any,
    text2: any
  ) => {
    console.log('=== 批量模式：模拟生成模式操作 ===');
    console.log('recordId:', recordId);
    console.log('extractedLabels:', extractedLabels);
    console.log('extractedStartTime:', extractedStartTime);
    console.log('extractedExpectedDate:', extractedExpectedDate);
    
    // 1. 构造虚拟的 selectedRecords 和 recordDetails
    const virtualSelectedRecords = [recordId];
    const virtualRecordDetails = [{
      id: recordId,
      fields: {
        'fldpvBfeC0': foreignId, // 外键ID字段
        'fld6Uw95kt': style,     // 样式字段
        'flde85ni4O': color,     // 颜色字段
        'fldG6LZnmU': text2      // 文本字段2
      }
    }];
    
    try {
      // 不再设置全局状态，直接通过overrideData传递数据
      console.log('批量模式：直接调用计算逻辑，传递起始时间:', extractedStartTime);
      
      // 3. 直接调用时效计算，通过overrideData传递所有必要数据
      const calculatedResults = await handleCalculateTimeline(true, {
        selectedRecords: virtualSelectedRecords,
        recordDetails: virtualRecordDetails,
        selectedLabels: extractedLabels,
        expectedDate: extractedExpectedDate,
        startTime: extractedStartTime // 直接传递起始时间，避免异步状态更新问题
      }, false); // showUI: false，批量模式下不显示时间轴UI
      
      console.log('批量模式：时效计算完成，结果:', calculatedResults);
      
      // 批量模式：更新UI显示最后处理记录的时间设置
      console.log('批量模式：更新UI显示时间设置');
      setExpectedDate(extractedExpectedDate);
      setStartTime(extractedStartTime);
      
      // 批量模式：自动保存逻辑
      console.log('批量模式：开始自动保存流程');
      
      // 检查计算结果
      if (!calculatedResults || calculatedResults.length === 0) {
        console.error('批量模式：时效计算结果为空，无法保存');
        throw new Error('时效计算结果为空，请检查流程配置和标签匹配');
      }
      
      // 自动触发保存
      console.log('批量模式：开始自动保存数据');
      await saveTimelineData({
        timelineResults: calculatedResults, // 使用直接返回的结果
        selectedRecords: virtualSelectedRecords,
        recordDetails: virtualRecordDetails,
        timelineAdjustments: {}, // 批量模式下没有手动调整
        labels: extractedLabels,
        expectedDate: extractedExpectedDate,
        startTime: extractedStartTime
      });
      
      console.log('批量模式：自动保存完成');
      
    } catch (error) {
      console.error('批量模式：处理失败', error);
      throw error; // 重新抛出错误让上层处理
    }
  };

  // 保存时效数据的核心逻辑（从确定并保存按钮提取）
  const saveTimelineData = async (batchData?: {
    timelineResults?: any[],
    selectedRecords?: string[],
    recordDetails?: any[],
    timelineAdjustments?: any,
    labels?: Record<string, any>, // 添加标签汇总
    expectedDate?: any, // 添加期望日期
    startTime?: any // 添加起始时间
  }) => {
    try {
      // 使用传入的数据或全局状态
      const currentTimelineResults = batchData?.timelineResults || timelineResults;
      const currentTimelineAdjustments = batchData?.timelineAdjustments || timelineAdjustments;
      
      if (currentTimelineResults.length > 0) {
        // 构造批量数据参数
        const batchDataForWriting = batchData ? {
          selectedRecords: batchData.selectedRecords || [],
          recordDetails: batchData.recordDetails || [],
          labels: batchData.labels, // 传递标签汇总
          expectedDate: batchData.expectedDate, // 传递期望日期
          startTime: batchData.startTime // 传递起始时间
        } : undefined;
        
        // 写入流程数据表
        const processRecordIds = await writeToProcessDataTable(currentTimelineResults, batchDataForWriting);
        
        // 写入货期记录表
        await writeToDeliveryRecordTable(currentTimelineResults, processRecordIds, currentTimelineAdjustments, batchDataForWriting);
        
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'success',
            message: Object.keys(currentTimelineAdjustments).length > 0 
              ? '已保存调整后的时效数据到流程数据表和货期记录表' 
              : '已保存计算的时效数据到流程数据表和货期记录表'
          });
        }
        
        return true; // 保存成功
      }
      return false; // 没有数据需要保存
    } catch (error) {
      console.error('保存数据时出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '保存数据失败，请重试'
        });
      }
      throw error; // 重新抛出错误
    }
  };

  const handleBatchProcess = async (rowCount: number) => {
    // 切换到批量处理流程时重置全局变量
    resetGlobalState();
    // 检查是否选择了表
    if (!selectedBatchTableId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'warning',
          message: '请先选择要处理的数据表'
        });
      }
      return;
    }
    
    setBatchProcessing(true);
    setBatchProgress({ current: 0, total: rowCount });
    
    try {
      // 使用选择的表而不是硬编码的表ID
      const batchTable = await bitable.base.getTable(selectedBatchTableId);
      
      // 获取表中的记录（限制数量）
      let records = [];
      if (selectedBatchViewId) {
        // 如果选择了视图，从视图中获取记录ID列表，然后获取记录
        const view = await batchTable.getViewById(selectedBatchViewId);
        const recordIdList = await view.getVisibleRecordIdList();
        const limitedRecordIds = recordIdList.slice(0, rowCount).filter(id => id !== undefined);
        
        // 批量获取记录
        for (const recordId of limitedRecordIds) {
          try {
            const record = await batchTable.getRecordById(recordId);
            // 将recordId添加到记录对象中，确保记录对象包含正确的ID
            record.recordId = recordId;
            records.push(record);
          } catch (error) {
            console.warn(`Failed to get record ${recordId}:`, error);
          }
        }
      } else {
        // 如果没有选择视图，从表中获取记录
        const recordsResult = await batchTable.getRecords({
          pageSize: rowCount
        });
        records = recordsResult.records || [];
      }
      const actualCount = Math.min(records.length, rowCount);
      
      if (actualCount === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: selectedBatchViewId ? '选择的视图中没有找到记录' : '选择的表中没有找到记录'
          });
        }
        return;
      }
      
      setBatchProgress({ current: 0, total: actualCount });
      
      // 获取新表的字段映射
      const fieldMetaList = await batchTable.getFieldMetaList();
      const fieldMapping: {[key: string]: string} = {};
      const optionMapping: {[fieldId: string]: {[optionId: string]: string}} = {};
      
      // 建立字段映射和选项映射
      for (const fieldMeta of fieldMetaList) {
        if (fieldMeta.name.match(/^标签([1-9]|10)$/)) {
          fieldMapping[fieldMeta.name] = fieldMeta.id;
          
          // 如果是选择字段，建立选项ID到名称的映射
          if (fieldMeta.property && fieldMeta.property.dataType && fieldMeta.property.dataType.property && fieldMeta.property.dataType.property.options) {
            optionMapping[fieldMeta.id] = {};
            for (const option of fieldMeta.property.dataType.property.options) {
              if (option.id && option.name) {
                optionMapping[fieldMeta.id][option.id] = option.name;
              }
            }
          }
        } else if (fieldMeta.name === '起始日期') {
          fieldMapping['起始日期'] = fieldMeta.id;
        } else if (fieldMeta.name === '客户期望日期') {
          fieldMapping['客户期望日期'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldGSdZgMI') {
          // 根据字段ID直接映射起始时间字段
          fieldMapping['起始时间'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldczh2nty') {
          // 款式字段映射
          fieldMapping['款式'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldk5fVYvW') {
          // 颜色字段映射
          fieldMapping['颜色'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldkKZecSv') {
          // foreign_id字段映射
          fieldMapping['foreign_id'] = fieldMeta.id;
        } else if (fieldMeta.name === 'oms看板record_id' ||  fieldMeta.id === 'fldlaYgpYO') {
          // 文本2字段映射 - 支持有空格和无空格的字段名称，以及直接ID匹配
          fieldMapping['文本2'] = fieldMeta.id;
        }
      }
      
      console.log('字段映射:', fieldMapping);
      console.log('选项映射:', optionMapping);
      console.log('所有字段元数据:', fieldMetaList.map(f => ({ id: f.id, name: f.name })));
      
      // 特别检查文本2字段
      const text2Fields = fieldMetaList.filter(f => f.name.includes('文本') || f.id === 'fldlaYgpYO');
      console.log('包含"文本"的字段或fldlaYgpYO:', text2Fields.map(f => ({ id: f.id, name: f.name })));
      
      let successCount = 0;
      let errorCount = 0;
      const errors: string[] = [];
      
      // 跟踪最后成功处理的记录的时间信息
      let lastSuccessfulStartTime: Date | null = null;
      let lastSuccessfulExpectedDate: Date | null = null;
      
      // 逐条处理记录
      for (let i = 0; i < actualCount; i++) {
        const record = records[i];
        setBatchProgress({ current: i + 1, total: actualCount });
        
        try {
          // 获取记录ID - 现在应该能正确获取到recordId
          const recordId = record.recordId || record.id || `record_${i + 1}`;
          console.log(`处理第 ${i + 1} 条记录:`, recordId);
          console.log(`记录对象结构:`, record);
          
          // 从记录中提取标签数据
          const extractedLabels: {[key: string]: string | string[]} = {};
          const recordFields = record.fields;
          
          // 提取标签1-10
          for (let labelNum = 1; labelNum <= 10; labelNum++) {
            const labelKey = `标签${labelNum}`;
            const fieldId = fieldMapping[labelKey];
            
            if (fieldId && recordFields[fieldId]) {
              const fieldValue = recordFields[fieldId];
              
              // 处理不同类型的字段值
              if (Array.isArray(fieldValue)) {
                // 多选字段或选项ID数组
                const values = fieldValue.map((item: any) => {
                  if (typeof item === 'string') {
                    // 如果是选项ID，从选项映射中查找对应的名称
                    if (optionMapping[fieldId] && optionMapping[fieldId][item]) {
                      return optionMapping[fieldId][item];
                    }
                    return item;
                  }
                  if (item && item.text) return item.text;
                  if (item && item.name) return item.name;
                  return '';
                }).filter(v => v);
                
                if (values.length > 0) {
                  // 处理可能包含逗号分隔的复合标签值，并与生成模式保持一致
                  const expandedValues: string[] = [];
                  values.forEach(value => {
                    if (typeof value === 'string' && value.includes(',')) {
                      // 拆分逗号分隔的值
                      const splitValues = value.split(',').map(v => v.trim()).filter(v => v !== '');
                      expandedValues.push(...splitValues);
                    } else {
                      expandedValues.push(value);
                    }
                  });
                  
                  // 与生成模式保持一致：单值返回字符串，多值返回数组
                  // 特殊处理：标签7始终返回数组结构
                  if (labelKey === '标签7') {
                    extractedLabels[labelKey] = expandedValues;
                  } else {
                    extractedLabels[labelKey] = expandedValues.length === 1 ? expandedValues[0] : expandedValues;
                  }
                }
              } else if (typeof fieldValue === 'string') {
                // 单行文本或选项ID
                let finalValue: string;
                if (optionMapping[fieldId] && optionMapping[fieldId][fieldValue]) {
                  finalValue = optionMapping[fieldId][fieldValue];
                } else {
                  finalValue = fieldValue;
                }
                
                // 特殊处理：标签7始终返回数组结构
                if (labelKey === '标签7') {
                  extractedLabels[labelKey] = [finalValue];
                } else {
                  extractedLabels[labelKey] = finalValue;
                }
              } else if (fieldValue && fieldValue.text) {
                // 富文本等
                const textValue = fieldValue.text;
                // 特殊处理：标签7始终返回数组结构
                if (labelKey === '标签7') {
                  extractedLabels[labelKey] = [textValue];
                } else {
                  extractedLabels[labelKey] = textValue;
                }
              } else if (fieldValue && typeof fieldValue === 'object') {
                // 处理公式字段和其他复杂对象
                if (fieldValue.value !== undefined) {
                  // 公式字段通常有value属性
                  if (Array.isArray(fieldValue.value)) {
                    const values = fieldValue.value.map((item: any) => {
                      if (typeof item === 'string') return item;
                      if (item && item.text) return item.text;
                      if (item && item.name) return item.name; // 处理选项的name属性
                      return '';
                    }).filter(v => v);
                    
                    if (values.length > 0) {
                      // 与生成模式保持一致：单值返回字符串，多值返回数组
                      // 特殊处理：标签7始终返回数组结构
                      if (labelKey === '标签7') {
                        extractedLabels[labelKey] = values;
                      } else {
                        extractedLabels[labelKey] = values.length === 1 ? values[0] : values;
                      }
                    }
                  } else if (typeof fieldValue.value === 'string') {
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [fieldValue.value];
                    } else {
                      extractedLabels[labelKey] = fieldValue.value;
                    }
                  } else if (fieldValue.value && fieldValue.value.name) {
                    // 单选字段的选项对象
                    const nameValue = fieldValue.value.name;
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [nameValue];
                    } else {
                      extractedLabels[labelKey] = nameValue;
                    }
                  }
                } else if (fieldValue.displayValue !== undefined) {
                  // 有些字段使用displayValue
                  if (Array.isArray(fieldValue.displayValue)) {
                    const values = fieldValue.displayValue.map((item: any) => {
                      if (typeof item === 'string') return item;
                      if (item && item.text) return item.text;
                      if (item && item.name) return item.name; // 处理选项的name属性
                      return '';
                    }).filter(v => v);
                    
                    if (values.length > 0) {
                      // 与生成模式保持一致：单值返回字符串，多值返回数组
                      // 特殊处理：标签7始终返回数组结构
                      if (labelKey === '标签7') {
                        extractedLabels[labelKey] = values;
                      } else {
                        extractedLabels[labelKey] = values.length === 1 ? values[0] : values;
                      }
                    }
                  } else if (typeof fieldValue.displayValue === 'string') {
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [fieldValue.displayValue];
                    } else {
                      extractedLabels[labelKey] = fieldValue.displayValue;
                    }
                  } else if (fieldValue.displayValue && fieldValue.displayValue.name) {
                    // 单选字段的选项对象
                    const nameValue = fieldValue.displayValue.name;
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [nameValue];
                    } else {
                      extractedLabels[labelKey] = nameValue;
                    }
                  }
                } else if (fieldValue.name) {
                  // 直接的选项对象，有name属性
                  const nameValue = fieldValue.name;
                  // 特殊处理：标签7始终返回数组结构
                  if (labelKey === '标签7') {
                    extractedLabels[labelKey] = [nameValue];
                  } else {
                    extractedLabels[labelKey] = nameValue;
                  }
                }
              }
            }
          }
          
          // 提取起始日期
          let extractedStartTime: Date | null = null;
          const startDateFieldId = fieldMapping['起始日期'] || fieldMapping['起始时间'];
          if (startDateFieldId && recordFields[startDateFieldId]) {
            const startDateValue = recordFields[startDateFieldId];
            if (typeof startDateValue === 'number') {
              extractedStartTime = new Date(startDateValue);
            } else if (typeof startDateValue === 'string') {
              extractedStartTime = new Date(startDateValue);
            } else if (Array.isArray(startDateValue) && startDateValue.length > 0) {
              // 处理数组格式的时间戳，如 [1757260800000]
              const timestamp = startDateValue[0];
              if (typeof timestamp === 'number') {
                extractedStartTime = new Date(timestamp);
              }
            }
          }
          
          // 提取客户期望日期
          let extractedExpectedDate: Date | null = null;
          const expectedDateFieldId = fieldMapping['客户期望日期'];
          if (expectedDateFieldId && recordFields[expectedDateFieldId]) {
            const expectedDateValue = recordFields[expectedDateFieldId];
            if (typeof expectedDateValue === 'number') {
              extractedExpectedDate = new Date(expectedDateValue);
            } else if (typeof expectedDateValue === 'string') {
              extractedExpectedDate = new Date(expectedDateValue);
            } else if (Array.isArray(expectedDateValue) && expectedDateValue.length > 0) {
              // 处理数组格式的时间戳，如 [1757260800000]
              const timestamp = expectedDateValue[0];
              if (typeof timestamp === 'number') {
                extractedExpectedDate = new Date(timestamp);
              }
            }
          }
          
          // 统一的字段提取函数（复用生成模式的逻辑）
          // 将提取的文本转换为富文本格式
          const createRichTextFormat = (text: string) => {
            return text ? [{ type: "text", text: text }] : null;
          };
          
          // 提取款式、颜色、foreign_id字段
          let extractedStyle: any = null;
          let extractedColor: any = null;
          let extractedForeignId: any = null;
          
          // 提取款式字段
          const styleFieldId = fieldMapping['款式'];
          if (styleFieldId && recordFields[styleFieldId]) {
            const styleText = extractText(recordFields[styleFieldId]);
            extractedStyle = createRichTextFormat(styleText);
          }
          
          // 提取颜色字段
          const colorFieldId = fieldMapping['颜色'];
          if (colorFieldId && recordFields[colorFieldId]) {
            const colorText = extractText(recordFields[colorFieldId]);
            extractedColor = createRichTextFormat(colorText);
          }
          
          // 提取foreign_id字段
          const foreignIdFieldId = fieldMapping['foreign_id'];
          if (foreignIdFieldId && recordFields[foreignIdFieldId]) {
            const foreignIdText = extractText(recordFields[foreignIdFieldId]);
            extractedForeignId = createRichTextFormat(foreignIdText);
          }
          
          // 提取文本2字段
          let extractedText2: any = null;
          const text2FieldId = fieldMapping['文本2'];
          console.log('文本2字段映射:', { fieldName: '文本2', fieldId: text2FieldId });
          console.log('记录字段keys:', Object.keys(recordFields));
          console.log('fldlaYgpYO字段值:', recordFields['fldlaYgpYO']);
          
          if (text2FieldId && recordFields[text2FieldId]) {
            extractedText2 = extractText(recordFields[text2FieldId]);
            console.log('提取后的extractedText2:', extractedText2);
          } else {
            console.log('文本2字段未找到或无数据:', { 
              fieldId: text2FieldId, 
              hasField: !!recordFields[text2FieldId],
              fieldValue: recordFields[text2FieldId]
            });
          }

          console.log(`记录 ${i + 1} 提取的数据:`, {
            labels: extractedLabels,
            startTime: extractedStartTime,
            expectedDate: extractedExpectedDate,
            style: extractedStyle,
            color: extractedColor,
            foreignId: extractedForeignId,
            text2: extractedText2
          });
          
          console.log(`记录 ${i + 1} 字段映射:`, fieldMapping);
          console.log(`记录 ${i + 1} 记录字段:`, Object.keys(recordFields));
          
          // 如果没有提取到任何标签，跳过这条记录
          if (Object.keys(extractedLabels).length === 0) {
            console.warn(`记录 ${i + 1} 没有找到任何标签数据，跳过处理`);
            errorCount++;
            errors.push(`记录 ${i + 1}: 没有找到标签数据`);
            continue;
          }
          
          // 使用模拟生成模式的方式进行时效计算和写入
          await simulateGenerationModeForBatch(
            recordId, 
            extractedLabels, 
            extractedStartTime, 
            extractedExpectedDate, 
            extractedStyle, 
            extractedColor, 
            extractedForeignId, 
            extractedText2
          );
          
          successCount++;
          
          // 记录最后成功处理的记录的时间信息
          lastSuccessfulStartTime = extractedStartTime;
          lastSuccessfulExpectedDate = extractedExpectedDate;
          
          // 添加延迟避免API限制
          if (i < actualCount - 1) {
            await new Promise(resolve => setTimeout(resolve, 100));
          }
          
        } catch (error) {
          console.error(`处理记录 ${i + 1} 失败:`, error);
          errorCount++;
          errors.push(`记录 ${i + 1}: ${(error as Error).message}`);
        }
      }
      
      // 显示处理结果
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: successCount > 0 ? 'success' : 'error',
          message: `批量处理完成！成功: ${successCount} 条，失败: ${errorCount} 条`
        });
      }
      
      // 如果有成功处理的记录，更新UI时间显示为最后一条成功记录的时间
      if (successCount > 0 && lastSuccessfulStartTime && lastSuccessfulExpectedDate) {
        console.log('批量处理完成：更新UI时间显示');
        console.log('最后成功记录的起始时间:', lastSuccessfulStartTime);
        console.log('最后成功记录的期望日期:', lastSuccessfulExpectedDate);
        
        setStartTime(lastSuccessfulStartTime);
        setExpectedDate(lastSuccessfulExpectedDate);
      }
      
      if (errors.length > 0) {
        console.error('批量处理错误详情:', errors);
      }
      
    } catch (error) {
      console.error('批量处理失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `批量处理失败: ${(error as Error).message}`
        });
      }
    } finally {
      setBatchProcessing(false);
      setBatchProgress({ current: 0, total: 0 });
    }
  };

  // 为批量处理优化的时效计算函数
  const calculateTimelineForBatch = async (
    labels: {[key: string]: string | string[]}, 
    startTime: Date | null, 
    expectedDate: Date | null,
    sourceRecordId: string,
    style?: any,
    color?: any,
    foreignId?: any,
    text2?: any
  ) => {
    try {
      // 批量模式：输出当前数据结构，便于与生成模式对比
      try {
        console.group('=== 批量模式：计算时效 - 当前数据结构 ===');
        console.log('sourceRecordId:', sourceRecordId);
        console.log('labels:', labels);
        console.log('startTime:', startTime);
        console.log('expectedDate:', expectedDate);
        console.log('style:', style);
        console.log('color:', color);
        console.log('foreignId:', foreignId);
        console.log('text2:', text2);
        console.groupEnd();
      } catch (logErr) {
        console.warn('批量模式结构化日志输出失败:', logErr);
      }
      // 1. 获取流程配置表数据
      const processConfigTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      const processConfigRecords = await processConfigTable.getRecords({
        pageSize: 5000
      });
      
      const processNodes = processConfigRecords.records || [];
      
      // 2. 构建业务选择的标签值集合
      const businessLabelValues = new Set<string>();
      console.log('批量模式 - 开始处理标签数据:', labels);
      
      for (const [labelKey, selectedValue] of Object.entries(labels)) {
        console.log(`批量模式 - 处理标签 ${labelKey}:`, selectedValue, '类型:', typeof selectedValue);
        
        if (selectedValue) {
          const values = Array.isArray(selectedValue) ? selectedValue : [selectedValue];
          values.forEach((value, index) => {
            console.log(`批量模式 - ${labelKey} 值${index}:`, value, '类型:', typeof value);
            
            if (typeof value === 'string' && value.trim()) {
              // 处理可能包含逗号分隔的复合标签值
              const splitValues = value.split(',').map(v => v.trim()).filter(v => v !== '');
              console.log(`批量模式 - ${labelKey} 分割后的值:`, splitValues);
              
              splitValues.forEach(splitValue => {
                businessLabelValues.add(splitValue);
                console.log(`批量模式 - 添加到业务标签集合: "${splitValue}"`);
              });
            }
          });
        }
      }
      
      console.log('批量模式 - 最终业务标签值集合:', Array.from(businessLabelValues));
      
      // 3. 匹配流程节点
      const matchedProcessNodes: any[] = [];
      console.log('批量模式 - 开始匹配流程节点，总节点数:', processNodes.length);
      
      for (const processNode of processNodes) {
        const processFields = processNode.fields;
        const nodeName = processFields[NODE_NAME_FIELD_ID];
        const processLabels = processFields[PROCESS_LABEL_FIELD_ID];
        const processOrder = processFields[PROCESS_ORDER_FIELD_ID];
        const weekendDays = processFields[WEEKEND_DAYS_FIELD_ID] || [];
        const excludedDates = processFields[EXCLUDED_DATES_FIELD_ID] || [];
        const startDateRule = processFields[START_DATE_RULE_FIELD_ID];
        const dateAdjustmentRule = processFields[DATE_ADJUSTMENT_RULE_FIELD_ID];
        
        // 处理节点名称
        let nodeNameText = '';
        if (typeof nodeName === 'string') {
          nodeNameText = nodeName;
        } else if (nodeName && nodeName.text) {
          nodeNameText = nodeName.text;
        }
        
        if (!nodeNameText) continue;
        
        // 处理流程标签数据，与生成模式保持一致
        const processLabelTexts: string[] = [];
        if (processLabels && Array.isArray(processLabels)) {
          for (const labelItem of processLabels) {
            const labelText = extractText(labelItem);
            if (labelText && labelText.trim()) {
              processLabelTexts.push(labelText.trim());
            }
          }
        }
        
        // 与生成模式保持一致：如果流程标签为空，跳过该节点
        if (processLabelTexts.length === 0) {
          console.log(`批量模式 - 流程节点 "${nodeNameText}" 标签为空，跳过`);
          continue;
        }
        
        console.log(`批量模式 - 检查流程节点 "${nodeNameText}":`, {
          流程标签: processLabelTexts,
          流程顺序: processOrder
        });
        
        // 处理流程标签匹配
        let isMatched = false;
        const matchedLabels: string[] = [];
        
        // 改为OR逻辑：只要有一个标签匹配就认为节点匹配
        for (const processLabelText of processLabelTexts) {
          console.log(`批量模式 - 检查流程标签: "${processLabelText}"`);
          
          // 对流程标签也进行分割处理，以支持复合标签值
          const processLabelValues = processLabelText.split(',').map(v => v.trim()).filter(v => v !== '');
          console.log(`批量模式 - 流程标签分割后: [${processLabelValues.join(', ')}]`);
          
          // 检查分割后的每个流程标签值是否在业务标签集合中
          for (const processLabelValue of processLabelValues) {
            if (businessLabelValues.has(processLabelValue)) {
              matchedLabels.push(processLabelValue);
              isMatched = true;
              console.log(`批量模式 - 流程节点 "${nodeNameText}" 匹配成功，匹配的标签: "${processLabelValue}"`);
              break; // 找到一个匹配就足够了
            } else {
              console.log(`批量模式 - 流程标签值 "${processLabelValue}" 未匹配`);
            }
          }
          
          if (isMatched) break; // 已经匹配，不需要继续检查其他标签
        }
        
        if (isMatched) {
          matchedProcessNodes.push({
            nodeName: nodeNameText,
            processOrder: typeof processOrder === 'number' ? processOrder : parseInt(processOrder) || 0,
            matchedLabels,
            weekendDays: Array.isArray(weekendDays) ? weekendDays : [],
            excludedDates: Array.isArray(excludedDates) ? excludedDates : [],
            startDateRule,
            dateAdjustmentRule
          });
          console.log(`批量模式 - 添加匹配的流程节点: "${nodeNameText}"`);
        } else {
          console.log(`批量模式 - 流程节点 "${nodeNameText}" 未匹配`);
        }
      }
      
      // 按流程顺序排序
      matchedProcessNodes.sort((a, b) => a.processOrder - b.processOrder);
      
      if (matchedProcessNodes.length === 0) {
        throw new Error('没有匹配的流程节点');
      }
      
      // 4. 获取时效数据并计算时间线
      const timelineTable = await bitable.base.getTable(TIMELINE_TABLE_ID);
      const timelineRecords = await timelineTable.getRecords({
        pageSize: 5000
      });
      
      // 获取时效表的标签字段映射（只需要获取一次）
      const timelineFieldMetaList = await timelineTable.getFieldMetaList();
      const timelineLabelFields: {[key: string]: string} = {};
      
      // 查找关系字段和计算方式字段
      let relationshipFieldId = '';
      let calculationMethodFieldId = '';
      
      for (const fieldMeta of timelineFieldMetaList) {
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          timelineLabelFields[labelKey] = fieldMeta.id;
        }
        // 查找关系字段
        if (fieldMeta.name === '关系' || fieldMeta.id === 'fldaIDAhab') {
          relationshipFieldId = fieldMeta.id;
        }
        // 查找时效计算方式字段
        if (fieldMeta.name === '时效计算方式' || fieldMeta.id === 'fldxfLZNUu') {
          calculationMethodFieldId = fieldMeta.id;
        }
      }
      
      // 构建时效数据索引
      const timelineIndexByNode = new Map<string, any[]>();
      
      for (const timelineRecord of timelineRecords.records || []) {
        const timelineFields = timelineRecord.fields;
        const timelineNodeName = timelineFields[TIMELINE_NODE_FIELD_ID];
        
        let timelineNodeNames: string[] = [];
        
        if (typeof timelineNodeName === 'string') {
          timelineNodeNames = timelineNodeName.split(',').map(name => name.trim());
        } else if (Array.isArray(timelineNodeName)) {
          timelineNodeNames = timelineNodeName.map(item => {
            if (typeof item === 'string') {
              return item.trim();
            } else if (item && item.text) {
              return item.text.trim();
            }
            return '';
          }).filter(name => name);
        } else if (timelineNodeName && timelineNodeName.text) {
          timelineNodeNames = timelineNodeName.text.split(',').map(name => name.trim());
        }
        
        for (const nodeName of timelineNodeNames) {
          const normalizedName = nodeName.toLowerCase();
          if (!timelineIndexByNode.has(normalizedName)) {
            timelineIndexByNode.set(normalizedName, []);
          }
          timelineIndexByNode.get(normalizedName)!.push({
            record: timelineRecord,
            fields: timelineFields
          });
        }
      }
      
      // 5. 计算每个节点的时效（遵循生成模式的匹配逻辑）
      const results: any[] = [];
      let cumulativeStartTime = startTime || new Date();
      
      for (const processNode of matchedProcessNodes) {
        console.log(`批量模式 - 开始处理流程节点: "${processNode.nodeName}"`);
        
        // 根据流程节点名称，在时效表中查找匹配的记录（与生成模式一致）
        const normalizedProcessName = processNode.nodeName.trim().toLowerCase();
        const candidateRecords = timelineIndexByNode.get(normalizedProcessName) || [];
        
        console.log(`批量模式 - 节点 "${processNode.nodeName}" 找到 ${candidateRecords.length} 个候选时效记录`);
        
        let timelineValue = null;
        let matchedTimelineRecord = null;
        
        // 收集所有匹配的候选记录（与生成模式保持一致）
        const matchedCandidates: any[] = [];
        
        // 在候选记录中进行标签匹配，收集所有匹配的记录
        for (const candidate of candidateRecords) {
          const { record: timelineRecord, fields: timelineFields } = candidate;
          
          // 进行完整的标签匹配逻辑（与生成模式保持一致）
          let isLabelsMatched = true;
          
          // 检查时效表中每个有值的标签是否都包含在业务标签中
          for (const [labelKey, timelineFieldId] of Object.entries(timelineLabelFields)) {
            const timelineLabelValue = timelineFields[timelineFieldId];
            
            // 处理时效表中的标签值
            let timelineLabelTexts: string[] = [];
            
            if (typeof timelineLabelValue === 'string' && timelineLabelValue.trim()) {
              timelineLabelTexts = [timelineLabelValue.trim()];
            } else if (timelineLabelValue && timelineLabelValue.text && timelineLabelValue.text.trim()) {
              timelineLabelTexts = [timelineLabelValue.text.trim()];
            } else if (Array.isArray(timelineLabelValue) && timelineLabelValue.length > 0) {
              // 多选字段，获取所有值
              timelineLabelTexts = timelineLabelValue.map(item => {
                if (typeof item === 'string') return item.trim();
                if (item && item.text) return item.text.trim();
                return '';
              }).filter(text => text);
            }
            
            // 如果时效表中该标签有值，则检查该标签的所有值是否都包含在业务标签中
            if (timelineLabelTexts.length > 0) {
              let allValuesMatched = true;
              
              for (const timelineText of timelineLabelTexts) {
                if (!businessLabelValues.has(timelineText)) {
                  allValuesMatched = false;
                  console.log(`批量模式 - 时效表标签 ${labelKey} 的值 "${timelineText}" 不在业务选择的标签中`);
                  break;
                }
              }
              
              if (!allValuesMatched) {
                console.log(`批量模式 - 时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 不完全包含在业务选择的标签中`);
                isLabelsMatched = false;
                break;
              } else {
                console.log(`批量模式 - 时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 完全匹配成功`);
              }
            }
            // 如果时效表中该标签为空，则跳过检查（空标签不影响匹配）
          }
          
          if (isLabelsMatched) {
            const timelineValueField = timelineFields[TIMELINE_FIELD_ID];
            const calculationMethodField = timelineFields[calculationMethodFieldId];
            const relationshipField = timelineFields[relationshipFieldId];
            
            if (timelineValueField !== null && timelineValueField !== undefined) {
              let candidateTimelineValue = 0;
              
              // 解析时效值（与生成模式保持一致）
              if (typeof timelineValueField === 'number') {
                candidateTimelineValue = timelineValueField;
              } else if (typeof timelineValueField === 'string') {
                const parsedValue = parseFloat(timelineValueField);
                candidateTimelineValue = isNaN(parsedValue) ? 0 : parsedValue;
              } else if (timelineValueField && typeof timelineValueField === 'object' && timelineValueField.value !== undefined) {
                candidateTimelineValue = timelineValueField.value;
              }
              
              // 获取计算方式
              let calculationMethod = '外部'; // 默认值
              if (calculationMethodField) {
                if (typeof calculationMethodField === 'string') {
                  calculationMethod = calculationMethodField;
                } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
                  calculationMethod = calculationMethodField.text;
                }
              }
              
              // 获取关系类型
              let relationshipType = '默认';
              if (relationshipField) {
                if (typeof relationshipField === 'string') {
                  relationshipType = relationshipField;
                } else if (relationshipField && typeof relationshipField === 'object' && relationshipField.text) {
                  relationshipType = relationshipField.text;
                }
              }
              
              // 根据计算方式转换时效值（小时转天）
              let convertedTimelineValue = 0;
              if (calculationMethod === '内部') {
                convertedTimelineValue = Math.round((candidateTimelineValue / 9) * 1000) / 1000;
              } else {
                convertedTimelineValue = Math.round((candidateTimelineValue / 24) * 1000) / 1000;
              }
              
              // 添加到匹配候选列表
              matchedCandidates.push({
                record: timelineRecord,
                timelineValue: convertedTimelineValue,
                originalHours: candidateTimelineValue,
                calculationMethod: calculationMethod,
                relationshipType: relationshipType
              });
            }
          }
        }
        
        // 处理匹配的候选记录（与生成模式保持一致）
        let finalTimelineValue = 0;
        let processingRule = '默认';
        
        if (matchedCandidates.length > 0) {
          // 获取主要关系类型（用于决定处理方式）
          const relationshipTypes = matchedCandidates.map(c => c.relationshipType);
          const primaryRelationshipType = relationshipTypes.find(type => type === '累加值' || type === '最大值') || '默认';
          
          // 使用关系字段决定处理方式（累加值、最大值、默认）
          processingRule = primaryRelationshipType || '默认';
          
          console.log('批量模式 - processingRule:', processingRule);
          
          if (processingRule === '累加值') {
            finalTimelineValue = matchedCandidates.reduce((sum, candidate) => sum + candidate.timelineValue, 0);
            const totalOriginalHours = matchedCandidates.reduce((sum, candidate) => sum + candidate.originalHours, 0);
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 累加值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`累加结果: 总计${totalOriginalHours}小时 → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          } else if (processingRule === '最大值') {
            finalTimelineValue = Math.max(...matchedCandidates.map(c => c.timelineValue));
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 最大值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`最大值结果: ${maxCandidate?.originalHours}小时(${maxCandidate?.calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = maxCandidate?.record || matchedCandidates[0].record;
          } else {
            finalTimelineValue = matchedCandidates[0].timelineValue;
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 默认处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`默认结果: 使用第一条记录 ${matchedCandidates[0].originalHours}小时(${matchedCandidates[0].calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          }
          
          timelineValue = finalTimelineValue;
        }
        
        // 计算节点时间（与生成模式保持一致）
        let nodeStartTime = new Date(cumulativeStartTime);
        let nodeEndTime = new Date(nodeStartTime);
        let nodeCalculationMethod = '外部'; // 默认计算方式
        
        // 如果有匹配的候选记录，使用其计算方式
        if (matchedCandidates.length > 0) {
          if (processingRule === '累加值') {
            nodeCalculationMethod = matchedCandidates[0].calculationMethod;
          } else if (processingRule === '最大值') {
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            nodeCalculationMethod = maxCandidate?.calculationMethod || matchedCandidates[0].calculationMethod;
          } else {
            nodeCalculationMethod = matchedCandidates[0].calculationMethod;
          }
        }
        
        if (timelineValue && timelineValue > 0) {
          // 根据计算方式调整开始时间
          const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          
          let endDate: Date;
          if (nodeCalculationMethod === '内部') {
            // 使用内部工作时间计算
            endDate = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            // 使用原有的24小时制计算
            endDate = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
          
          nodeStartTime = adjustedStartTime;
          nodeEndTime = endDate;
        }
        
        results.push({
          processOrder: processNode.processOrder,
          nodeName: processNode.nodeName,
          matchedLabels: processNode.matchedLabels,
          timelineValue: timelineValue,
          estimatedStart: formatDate(nodeStartTime), // 使用默认格式，与生成模式一致
          estimatedEnd: formatDate(nodeEndTime), // 使用默认格式，与生成模式一致
          timelineRecordId: matchedTimelineRecord ? (matchedTimelineRecord.id || matchedTimelineRecord.recordId) : null,
          calculationMethod: nodeCalculationMethod, // 使用实际的计算方式
          weekendDaysConfig: processNode.weekendDays,
          skippedWeekends: 0,
          actualDays: calculateActualDays(formatDate(nodeStartTime), formatDate(nodeEndTime)), // 使用一致的格式
          startDateRule: processNode.startDateRule,
          dateAdjustmentRule: processNode.dateAdjustmentRule,
          // 新增：保存所有匹配记录的信息（用于累加情况）
          allMatchedRecords: matchedCandidates.length > 1 ? matchedCandidates.map(candidate => ({
            recordId: candidate.record.id || candidate.record.recordId || candidate.record._id || candidate.record.record_id,
            timelineValue: candidate.timelineValue,
            originalHours: candidate.originalHours,
            calculationMethod: candidate.calculationMethod,
            relationshipType: candidate.relationshipType
          })) : null,
          // 新增：标识是否为累加处理
          isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1
        });
        
        // 更新累积时间
        if (timelineValue && timelineValue > 0) {
          cumulativeStartTime = new Date(nodeEndTime);
        }
      }
      
      console.log('批量计算结果:', results);
      
      // 6. 写入数据到货期记录表和流程数据表
      if (results.length > 0) {
        console.log('=== 批量模式：开始写入数据 ===');
        console.log('批量写入 - sourceRecordId:', sourceRecordId);
        console.log('批量写入 - labels:', labels);
        console.log('批量写入 - expectedDate:', expectedDate);
        console.log('批量写入 - style:', style);
        console.log('批量写入 - color:', color);
        console.log('批量写入 - foreignId:', foreignId);
        console.log('批量写入 - text2:', text2);
        console.log('批量写入 - startTime:', startTime);
        
        try {
          // 为标准写入函数准备数据：构造临时的数据结构
          console.log('批量写入 - 设置临时状态以适配标准写入函数');
          
          // 构造临时的recordDetails，包含当前记录的字段信息
          const tempRecordDetails = [{
            id: sourceRecordId,
            fields: {
              'fldpvBfeC0': foreignId, // 外键ID字段
              'fld6Uw95kt': style,     // 样式字段
              'flde85ni4O': color,     // 颜色字段
              'fldG6LZnmU': text2      // 文本字段2
            }
          }];
          
          // 构造批量数据对象（包含必要的业务字段）
          const batchDataForWriting = {
            selectedRecords: [sourceRecordId],
            recordDetails: tempRecordDetails,
            labels,           // 标签汇总（对象）
            expectedDate,     // 客户期望日期（Date）
            startTime         // 起始时间（Date）
          };
          
          console.log('批量写入 - 临时数据构造完成，开始调用标准写入函数');
          console.log('批量写入 - batchDataForWriting:', batchDataForWriting);
          
          // 写入流程数据表 - 使用标准函数，传递批量数据
          console.log('批量写入 - 调用标准writeToProcessDataTable函数');
          const processRecordIds = await writeToProcessDataTable(results, batchDataForWriting);
          console.log('批量写入 - 流程数据表写入完成，记录ID:', processRecordIds);
          
          // 写入货期记录表 - 使用标准函数，传递批量数据和空的调整信息
          console.log('批量写入 - 调用标准writeToDeliveryRecordTable函数');
          await writeToDeliveryRecordTable(results, processRecordIds, {}, batchDataForWriting);
          console.log('批量写入 - 货期记录表写入完成');
          
          // 批量写入成功后，设置全局状态以便快照保存
          console.log('批量写入 - 设置全局状态以便快照保存');
          setSelectedRecords([sourceRecordId]);
          setRecordDetails(tempRecordDetails);
          setSelectedLabels(labels);
          setCurrentStyleText(extractText(style));
          setCurrentColorText(extractText(color));
          setCurrentText2(extractText(text2));
          setCurrentForeignId(extractText(foreignId));
          setExpectedDate(expectedDate);
          setStartTime(startTime);
          
        } catch (error) {
          console.error('批量写入失败:', error);
          throw error;
        }
        
        console.log('=== 批量模式：数据写入完成 ===');
      }
      
    } catch (error) {
      console.error('批量时效计算失败:', error);
      throw error;
    }
  };



  // 执行定价数据查询
  const executeQuery = async (packId: string, packType: string) => {
    setQueryLoading(true);
    try {
      // 使用 apiService 中的函数
      const data = await executePricingQuery(packId, packType, selectedLabels);
      setQueryResults(data);
      
      // 处理品类属性填充到标签8的逻辑保持不变
      if (data && data.length > 0) {
        const label8Options = labelOptions['标签8'] || [];
        const matchingCategoryValues: string[] = [];
        
        data.forEach((record: any) => {
          if (record.品类属性 && record.品类属性.trim() !== '') {
            const categoryValue = record.品类属性.trim();
            const matchingOption = label8Options.find(option => 
              option.value === categoryValue || option.label === categoryValue
            );
            
            if (matchingOption && !matchingCategoryValues.includes(categoryValue)) {
              matchingCategoryValues.push(categoryValue);
            }
          }
        });
        
        if (matchingCategoryValues.length > 0) {
          setSelectedLabels(prev => ({
            ...prev,
            '标签8': matchingCategoryValues
          }));
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已将 ${matchingCategoryValues.length} 个品类属性填充到标签8: ${matchingCategoryValues.join(', ')}`
            });
          }
        }
      }
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '查询成功'
        });
      }
      
    } catch (error: any) {
      console.error('数据库查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `数据库查询失败: ${error.message}`
        });
      }
    } finally {
      setQueryLoading(false);
    }
  };

  // 执行二次工艺查询
  const executeSecondaryProcessQueryLocal = async (packId: string, packType: string) => {
    setSecondaryProcessLoading(true);
    try {
      const data = await executeSecondaryProcessQuery(packId, packType);
      setSecondaryProcessResults(data);
      
      // 处理二次工艺填充到标签7的逻辑
      if (data && data.length > 0) {
        const label7Options = labelOptions['标签7'] || [];
        const matchingProcessValues: string[] = [];
        
        data.forEach((record: any) => {
          if (record.costs_type && record.costs_type.trim() !== '') {
            const processValue = record.costs_type.trim();
            const matchingOption = label7Options.find(option => 
              option.value === processValue || option.label === processValue
            );
            
            if (matchingOption && !matchingProcessValues.includes(processValue)) {
              matchingProcessValues.push(processValue);
            }
          }
        });
        
        if (matchingProcessValues.length > 0) {
          setSelectedLabels(prev => ({
            ...prev,
            '标签7': matchingProcessValues
          }));
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已将 ${matchingProcessValues.length} 个二次工艺填充到标签7: ${matchingProcessValues.join(', ')}`
            });
          }
        }
      }
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '二次工艺查询成功'
        });
      }
    } catch (error: any) {
      console.error('二次工艺查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `二次工艺查询失败: ${error.message}`
        });
      }
    } finally {
      setSecondaryProcessLoading(false);
    }
  };

  // 执行定价详情查询
  const executePricingDetailsQueryLocal = async (packId: string) => {
    setPricingDetailsLoading(true);
    try {
      const data = await executePricingDetailsQuery(packId);
      setPricingDetailsResults(data);
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '定价详情查询成功'
        });
      }
    } catch (error: any) {
      console.error('定价详情查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `定价详情查询失败: ${error.message}`
        });
      }
    } finally {
      setPricingDetailsLoading(false);
    }
  };

  // 处理数据库查询
  const handleQueryDatabase = async (record: any) => {
    // 从记录字段中提取 packId 和 packType
    let packId = '';
    let packType = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    // 提取 pack_type (fldSAF9qXe)
    if (record.fields.fldSAF9qXe && record.fields.fldSAF9qXe.text) {
      packType = record.fields.fldSAF9qXe.text;
    }
    
    if (!packId || !packType) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id 或 pack_type)'
        });
      }
      return;
    }
    
    await executeQuery(packId, packType);
  };

  // 处理二次工艺查询
  const handleSecondaryProcessQuery = async (record: any) => {
    // 从记录字段中提取 packId 和 packType
    let packId = '';
    let packType = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    // 提取 pack_type (fldSAF9qXe)
    if (record.fields.fldSAF9qXe && record.fields.fldSAF9qXe.text) {
      packType = record.fields.fldSAF9qXe.text;
    }
    
    if (!packId || !packType) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id 或 pack_type)'
        });
      }
      return;
    }
    
    await executeSecondaryProcessQueryLocal(packId, packType);
  };

  // 处理定价详情查询
  const handlePricingDetailsQuery = async (record: any) => {
    // 从记录字段中提取 packId
    let packId = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    if (!packId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id)'
        });
      }
      return;
    }
    
    await executePricingDetailsQueryLocal(packId);
  };



  // 获取记录详情的函数
  const fetchRecordDetails = async (recordIdList: string[]) => {

    try {
      const table = await bitable.base.getTable(TABLE_ID);
      
      // 并行获取所有记录详情
      const recordPromises = recordIdList.map(recordId => 
        table.getRecordById(recordId)
      );
      
      const records = await Promise.all(recordPromises);
      
      const recordValList = records.map((record, index) => {
        console.log(`记录 ${recordIdList[index]} 的详情:`, record);
        console.log(`记录 ${recordIdList[index]} 的fldpvBfeC0字段:`, record.fields['fldpvBfeC0']);
        return {
          id: recordIdList[index],
          fields: record.fields
        };
      });
      
      setRecordDetails(recordValList);
    } catch (error) {
      console.error('获取记录详情失败:', error);
    }
  };

  // 选择记录
  const handleSelectRecords = async () => {
    // 切换版单数据时重置全局变量，清空旧结果与回填状态
    resetGlobalState();
    setLoading(true);
    // 清空标签选择
    setSelectedLabels({});
    setExpectedDate(null);
    
    try {
      // 修改这里：使用正确的 API
      const recordIdList = await bitable.ui.selectRecordIdList(TABLE_ID, VIEW_ID);
      
      setSelectedRecords(recordIdList);
      
      // 获取记录的详细信息
      if (recordIdList.length > 0) {
        // 并行获取记录详情和字段元数据
        const table = await bitable.base.getTable(TABLE_ID);
        const [recordPromises, fieldMetaList] = await Promise.all([
          Promise.all(recordIdList.map(recordId => table.getRecordById(recordId))),
          table.getFieldMetaList()
        ]);
        
        const recordValList = recordPromises.map((record, index) => ({
          id: recordIdList[index],
          fields: record.fields
        }));
        
        if (recordValList.length > 0) {
          const firstRecord = recordValList[0];
          const extractedLabels: {[key: string]: string} = {};
          
          // 建立字段名到字段ID的映射
          const fieldNameToId: {[key: string]: string} = {};
          for (const fieldMeta of fieldMetaList) {
            fieldNameToId[fieldMeta.name] = fieldMeta.id;
          }
          
          // 提取标签值的辅助函数
          const extractFieldValue = (fieldName: string) => {
            const fieldId = fieldNameToId[fieldName];
            if (fieldId && firstRecord.fields[fieldId]) {
              const fieldValue = firstRecord.fields[fieldId];
              
              // 优先处理数组格式（公式字段）
              if (Array.isArray(fieldValue) && fieldValue.length > 0) {
                const firstItem = fieldValue[0];
                if (typeof firstItem === 'string') {
                  return firstItem;
                } else if (firstItem && (firstItem.text || firstItem.name)) {
                  return firstItem.text || firstItem.name;
                }
              }
              // 处理对象格式（普通字段）
              else if (typeof fieldValue === 'object' && fieldValue !== null) {
                if (fieldValue.text) {
                  return fieldValue.text;
                } else if (fieldValue.name) {
                  return fieldValue.name;
                }
              }
              // 处理字符串格式
              else if (typeof fieldValue === 'string') {
                return fieldValue.trim();
              }
            }
            return '';
          };
          
          // 直接通过字段ID提取fld6Uw95kt的值
          const getFieldValueById = (fieldId: string) => {
            if (fieldId && firstRecord.fields[fieldId]) {
              const fieldValue = firstRecord.fields[fieldId];
              
              // 优先处理数组格式（公式字段）
              if (Array.isArray(fieldValue) && fieldValue.length > 0) {
                const firstItem = fieldValue[0];
                if (typeof firstItem === 'string') {
                  return firstItem;
                } else if (firstItem && (firstItem.text || firstItem.name)) {
                  return firstItem.text || firstItem.name;
                }
              }
              // 处理对象格式（普通字段）
              else if (typeof fieldValue === 'object' && fieldValue !== null) {
                if (fieldValue.text) {
                  return fieldValue.text;
                } else if (fieldValue.name) {
                  return fieldValue.name;
                }
              }
              // 处理字符串格式
              else if (typeof fieldValue === 'string') {
                return fieldValue.trim();
              }
            }
            return '';
          };
          
          // 提取fld6Uw95kt字段的值
          const mainRecordDisplayValue = getFieldValueById('fld6Uw95kt') || firstRecord.id;
          
          // 将这个值存储到recordDetails中，以便在UI中使用
          const updatedRecordValList = recordValList.map((record, index) => ({
            ...record,
            displayValue: index === 0 ? mainRecordDisplayValue : record.id
          }));
          
          setRecordDetails(updatedRecordValList);
          
          // 提取各个标签的值
          const label2Value = extractFieldValue('品类名称');
          const label3Value = extractFieldValue('大类名称');
          const label4Value = extractFieldValue('中类名称');
          const label5Value = extractFieldValue('小类名称');
          const label6Value = extractFieldValue('工艺难易度');
          
          // 设置提取到的标签值
          const newSelectedLabels: {[key: string]: string | string[]} = {};
          if (label2Value) newSelectedLabels['标签2'] = label2Value;
          if (label3Value) newSelectedLabels['标签3'] = label3Value;
          if (label4Value) newSelectedLabels['标签4'] = label4Value;
          if (label5Value) newSelectedLabels['标签5'] = label5Value;
          if (label6Value) newSelectedLabels['标签6'] = label6Value;
          
          // 添加标签10的自动填充
          newSelectedLabels['标签10'] = ['复版', '开货版不打版'];
          
          // 保留用户手动选择的标签1、7、8、9
          setSelectedLabels(prev => ({
            ...prev,
            ...newSelectedLabels
          }));
          
          console.log('自动提取的标签值:', newSelectedLabels);
          
          // 显示提取结果的提示
          if (Object.keys(newSelectedLabels).length > 0 && bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已自动提取 ${Object.keys(newSelectedLabels).length} 个标签值`
            });
          }
          
          // 自动执行所有三个查询 - 对第一条记录顺序执行查询
          // 顺序执行查询，避免 loading 状态冲突
          try {
            await handleQueryDatabase(recordValList[0]);
            await handleSecondaryProcessQuery(recordValList[0]);
            await handlePricingDetailsQuery(recordValList[0]);
          } catch (queryError) {
            console.error('自动查询出错:', queryError);
          }
        }
      } else {
        setRecordDetails([]);
      }
    } catch (error) {
      console.error('选择记录时出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '选择记录时出错，请重试'
        });
      }
    } finally {
      setLoading(false);
    }
  };

  // 清空选中的记录
  const handleClearRecords = () => {
    setSelectedRecords([]);
    setRecordDetails([]);
    setQueryResults([]);
    setSecondaryProcessResults([]);
    setPricingDetailsResults([]);
    // 同时清空标签选择
    setSelectedLabels({});
    setExpectedDate(null);
  };

  // 定价数据表格列定义
  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
      key: 'id',
    },
    {
      title: 'Pack ID',
      dataIndex: 'pack_id',
      key: 'pack_id',
    },
    {
      title: 'Pack Type',
      dataIndex: 'pack_type',
      key: 'pack_type',
    },
    {
      title: '物料编码',
      dataIndex: 'material_code',
      key: 'material_code',
    },
    {
      title: '一级分类',
      dataIndex: 'category1_name',
      key: 'category1_name',
    },
    {
      title: '二级分类',
      dataIndex: 'category2_name',
      key: 'category2_name',
    },
    {
      title: '三级分类',
      dataIndex: 'category3_name',
      key: 'category3_name',
    },
    {
      title: '品类属性',
      dataIndex: '品类属性',
      key: '品类属性',
    },
  ];

  // 二次工艺表格列定义
  const secondaryProcessColumns = [
    {
      title: 'ID',
      dataIndex: 'id',
      key: 'id',
    },
    {
      title: 'Foreign ID',
      dataIndex: 'foreign_id',
      key: 'foreign_id',
    },
    {
      title: 'Pack Type',
      dataIndex: 'pack_type',
      key: 'pack_type',
    },
    {
      title: '项目',
      dataIndex: 'costs_item',
      key: 'costs_item',
    },
    {
      title: '二次工艺',
      dataIndex: 'costs_type',
      key: 'costs_type',
    },
    {
      title: '备注',
      dataIndex: 'remarks',
      key: 'remarks',
    },
  ];

  // 定价详情表格列定义
  const pricingDetailsColumns = [
    {
      title: 'Pack ID',
      dataIndex: 'pack_id',
      key: 'pack_id',
    },
    {
      title: '倍率',
      dataIndex: '倍率',
      key: '倍率',
    },
    {
      title: '加工费',
      dataIndex: '加工费',
      key: '加工费',
    },
    {
      title: '总价',
      dataIndex: '总价',
      key: '总价',
    },
  ];

  return (
    <div style={{ padding: '20px' }}>
      {/* 入口选择弹窗 */}
      <Modal
        title="请选择功能入口"
        visible={modeSelectionVisible}
        footer={null}
        onCancel={() => setModeSelectionVisible(false)}
        maskClosable={false}
      >
        <div style={{ display: 'flex', gap: 24, justifyContent: 'center', padding: '12px 8px 8px', flexWrap: 'wrap' }}>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('generate')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>生成流程日期</Title>
            <Text type='tertiary'>基于业务数据计算并生成节点时间线</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('generate')}>进入</Button>
            </div>
          </Card>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('adjust')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>调整流程日期</Title>
            <Text type='tertiary'>读取货期记录，精确还原时间线</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('adjust')}>进入</Button>
            </div>
          </Card>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('batch')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>批量生成</Title>
            <Text type='tertiary'>批量生成多条流程记录</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('batch')}>进入</Button>
            </div>
          </Card>
        </div>
      </Modal>

      {mode === 'generate' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #3b82f6, #1d4ed8)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            数据查询工具
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>基于业务数据计算并生成节点时间线</Text>
        </div>
      )}
      {mode === 'batch' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #10b981, #059669)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            批量生成工具
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>批量生成多条流程记录，提高工作效率</Text>
        </div>
      )}
      {mode === 'adjust' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #f59e0b, #d97706)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            调整流程日期
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>读取货期记录，精确还原时间线</Text>
        </div>
      )}
      {/* 功能入口切换与调整入口 */}
      {mode !== null && (
        <div style={{ margin: '18px 0 14px' }}>
          <Space spacing={16} align='center'>
            <Select value={mode} onChange={(v) => setMode(v as any)}
              optionList={[
                { value: 'generate', label: '生成流程日期' }, 
                { value: 'adjust', label: '调整流程日期' },
                { value: 'batch', label: '批量生成' }
              ]} />
            {mode === 'adjust' && (
              <Space spacing={12} align='center'>
                <Button type="primary" onClick={async () => {
                  try {
                    const selection = await bitable.base.getSelection();
                    const recordId = selection?.recordId || '';
                    const tableId = selection?.tableId || '';
                    if (!recordId) {
                      if (bitable.ui.showToast) {
                        await bitable.ui.showToast({ toastType: 'warning', message: '请先在数据表中选中一条货期记录' });
                      }
                      return;
                    }
                    if (tableId && tableId !== DELIVERY_RECORD_TABLE_ID) {
                      if (bitable.ui.showToast) {
                        await bitable.ui.showToast({ toastType: 'warning', message: '请在货期记录表中选择记录' });
                      }
                      return;
                    }
                    setSelectedDeliveryRecordId(recordId);
                    await loadProcessDataFromDeliveryRecord(recordId);
                  } catch (e) {
                    console.error('读取当前选中记录失败:', e);
                    if (bitable.ui.showToast) {
                      await bitable.ui.showToast({ toastType: 'error', message: '读取当前选中记录失败' });
                    }
                  }
                }}>读取当前选中记录并还原流程数据</Button>
              </Space>
            )}
            {/* 批量处理功能 - 只在批量模式下显示 */}
          </Space>
        </div>
      )}
      
      {/* 时效计算结果模态框 */}
      <Modal
        title="预计开始和完成时间"
        visible={timelineVisible}
        onCancel={() => {
          setTimelineVisible(false);
          setTimelineAdjustments({}); // 关闭时重置调整
          setDeliveryMarginDeductions(0); // 关闭时重置交期余量扣减
          setCompletionDateAdjustment(0); // 关闭时重置最后流程完成日期调整
        }}
        footer={
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <Space align="center">
              <Text>缓冲期(天)：</Text>
              <InputNumber
                min={0}
                step={1}
                value={baseBufferDays}
                onChange={(val) => {
                  const n = Number(val);
                  setBaseBufferDays(Number.isFinite(n) && n >= 0 ? n : 0);
                }}
                style={{ width: 90 }}
              />
              <Button onClick={resetTimelineAdjustments}>
                重置所有调整
              </Button>
            </Space>
            <Button 
              type="primary" 
              onClick={async () => {
                try {
                  // 如果有当前批量记录信息，使用批量数据进行保存
                  if (currentBatchRecord) {
                    console.log('使用批量记录数据进行保存:', currentBatchRecord);
                    await saveTimelineData({
                      timelineResults: timelineResults,
                      selectedRecords: currentBatchRecord.selectedRecords,
                      recordDetails: currentBatchRecord.recordDetails,
                      timelineAdjustments: timelineAdjustments,
                      labels: currentBatchRecord.labels,
                      expectedDate: currentBatchRecord.expectedDate,
                      startTime: currentBatchRecord.startTime
                    });
                  } else {
                    // 普通模式保存
                    await saveTimelineData();
                  }
                } catch (error) {
                  // 错误已在saveTimelineData中处理
                }
                setTimelineVisible(false);
                // 清除批量记录信息
                setCurrentBatchRecord(null);
              }}
            >
              确定并保存
            </Button>
          </div>
        }
        width={900}
      >
        <div style={{ maxHeight: '80vh', overflowY: 'auto' }}>
          {timelineResults.length === 0 ? (
            <div style={{ textAlign: 'center', padding: '40px' }}>
              <Text type="tertiary">未找到匹配的时效数据</Text>
            </div>
          ) : (
            <div>
              <div style={{ marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '12px' }}>
                <Text strong>起始时间</Text>
                <DatePicker
                  style={{ width: 280 }}
                  placeholder="请选择起始时间"
                  value={startTime}
                  onChange={(date) => {
                    setStartTime(date);
                  }}
                  type="dateTime"
                  format="yyyy-MM-dd HH:mm"
                />
              </div>
              {timelineResults.map((result, index) => {
                const adjustment = timelineAdjustments[index] || 0;
                const baseValue = (typeof result.timelineValue === 'number')
                  ? result.timelineValue
                  : (typeof result.adjustedTimelineValue === 'number')
                    ? result.adjustedTimelineValue
                    : 0;
                const adjustedValue = baseValue + adjustment;
                
                // 检查是否为周转周期节点
                const isTurnoverNode = result.nodeName === '周转周期';
                
                // 检查是否存在周转周期为零的情况
                const hasTurnoverNodeWithZero = timelineResults.some((r, i) => {
                  if (r.nodeName === '周转周期') {
                    const adj = timelineAdjustments[i] || 0;
                    const baseVal = (typeof r.timelineValue === 'number')
                      ? r.timelineValue
                      : (typeof r.adjustedTimelineValue === 'number')
                        ? r.adjustedTimelineValue
                        : 0;
                    return (baseVal + adj) === 0;
                  }
                  return false;
                });
                
                // 当前节点是否为零值的周转周期节点
                const isCurrentTurnoverZero = isTurnoverNode && adjustedValue === 0;
                
                // 计算动态缓冲期，用于限制节点增加操作
                const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                
                // 新的复合限制逻辑：
                // 1. 如果缓冲期 > 0，允许操作
                // 2. 如果缓冲期 = 0，进一步判断交期余量
                // 3. 如果缓冲期 = 0 且交期余量 <= 0，禁止操作
                let hasNegativeBuffer = false;
                
                // 计算交期余量（仅用于显示，不用于限制）
                let deliveryMargin = 0;
                if (timelineResults.length > 0) {
                  // 获取有效的最后流程完成日期（与交期余量计算逻辑保持一致）
                  let effectiveLastProcess = null;
                  let lastCompletionDate = null;
                  
                  for (let i = timelineResults.length - 1; i >= 0; i--) {
                    const process = timelineResults[i];
                    const processDate = new Date(process.estimatedEnd);
                    
                    if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                      effectiveLastProcess = process;
                      lastCompletionDate = processDate;
                      break;
                    }
                  }
                  
                  if (!effectiveLastProcess) {
                    effectiveLastProcess = timelineResults[timelineResults.length - 1];
                    lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                  }
                  
                  // 计算最后完成日期（考虑调整）+ 动态缓冲期
                  const adjustedCompletionDate = new Date(lastCompletionDate);
                  adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                  
                  const deliveryDate = new Date(adjustedCompletionDate);
                  deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
                  
                  if (expectedDate) {
                    // 有客户期望日期：交期余量 = 客户期望日期 - (最后流程完成 + 缓冲期)
                    const timeDiff = expectedDate.getTime() - deliveryDate.getTime();
                    const baseDeliveryMargin = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                    deliveryMargin = baseDeliveryMargin - deliveryMarginDeductions;
                  } else {
                    // 无客户期望日期：交期余量 = (最后流程完成 + 缓冲期) - 今天
                    const today = new Date();
                    today.setHours(0, 0, 0, 0);
                    const timeDiff = deliveryDate.getTime() - today.getTime();
                    const baseDeliveryMargin = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                    deliveryMargin = baseDeliveryMargin - deliveryMarginDeductions;
                  }
                }
                
                // 执行复合限制判断 - 只有在缓冲期为0时才检查最终限制
                let canIncrease = false;
                if (dynamicBufferDays > 0) {
                  // 1. 缓冲期 > 0，允许操作
                  canIncrease = true;
                } else {
                  // 2. 缓冲期 = 0，检查最终限制：最后节点预计完成时间是否已达到客户期望日期
                  if (expectedDate && timelineResults.length > 0) {
                    // 获取有效的最后流程完成日期
                    let effectiveLastProcess = null;
                    let lastCompletionDate = null;
                    
                    for (let i = timelineResults.length - 1; i >= 0; i--) {
                      const process = timelineResults[i];
                      const processDate = new Date(process.estimatedEnd);
                      
                      if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                        effectiveLastProcess = process;
                        lastCompletionDate = processDate;
                        break;
                      }
                    }
                    
                    if (!effectiveLastProcess) {
                      effectiveLastProcess = timelineResults[timelineResults.length - 1];
                      lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                    }
                    
                    // 计算最后流程完成日期（包含调整）
                    const adjustedCompletionDate = new Date(lastCompletionDate);
                    adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                    
                    // 检查是否已达到客户期望日期
                    const timeDiffToExpected = expectedDate.getTime() - adjustedCompletionDate.getTime();
                    const daysToExpected = Math.ceil(timeDiffToExpected / (1000 * 60 * 60 * 24));
                    canIncrease = daysToExpected > 0; // 只有当还有剩余天数时才允许调整
                  } else {
                    // 无客户期望日期时，理论上可以无限调整
                    canIncrease = true;
                  }
                }
                hasNegativeBuffer = !canIncrease;
                
                return (
                  <Card key={index} style={{ marginBottom: '8px', padding: '12px', position: 'relative' }}>
                    <div style={{ position: 'absolute', top: '12px', left: '12px', zIndex: 1, display: 'flex', alignItems: 'center', gap: '16px' }}>
  <Title heading={6} style={{ margin: 0, color: '#1890ff', fontSize: '18px' }}>
    {result.processOrder && `${result.processOrder}. `}{result.nodeName}
    {result.isAccumulated && result.allMatchedRecords ? (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#000000', 
        fontWeight: 'normal' 
      }}>
        (累加 {result.allMatchedRecords.length} 条记录: {result.allMatchedRecords.map(record => record.recordId).join(', ')})
      </span>
    ) : result.timelineRecordId ? (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#000000', 
        fontWeight: 'normal' 
      }}>
        ({result.timelineRecordId})
      </span>
    ) : (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#ff4d4f', 
        fontWeight: 'normal' 
      }}>
        (无匹配记录)
      </span>
    )}
  </Title>
  
  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
    <Text style={{ fontSize: '14px', color: '#666', whiteSpace: 'nowrap' }}>实际完成：</Text>
    <DatePicker
      size="small"
      placeholder="选择日期"
      value={actualCompletionDates[index] || null}
      onChange={(date) => {
        setActualCompletionDates(prev => ({
          ...prev,
          [index]: date
        }));
        
        // 自动设置调整量：按工作日规则（考虑内部/外部、休息日、跳过日期）
        try {
          const currentResult = timelineResults[index];
          const startStr = currentResult?.estimatedStart;
          if (startStr && date) {
            const startDate = new Date(startStr);
            if (!isNaN(startDate.getTime())) {
              const calcRaw = currentResult?.calculationMethod || '外部';
              const calcMethod = (calcRaw === '内部' || calcRaw === 'internal') ? '内部' : '外部';
              const weekendDays = currentResult?.weekendDaysConfig || currentResult?.weekendDays || [];
              const excludedDates = Array.isArray(currentResult?.excludedDates) ? currentResult!.excludedDates : [];

              // 与正向计算一致：先对起始时间应用工作时间调整
              const adjustedStart = adjustToNextWorkingHour(startDate, calcMethod, weekendDays, excludedDates);
              const targetDate = new Date(date);

              // 使用二分搜索反推工作日数（按0.5天粒度），使得正向计算的结束时间尽量贴近目标日期
              const dayMs = 1000 * 60 * 60 * 24;
              const approxNatural = Math.max(0, (targetDate.getTime() - adjustedStart.getTime()) / dayMs);
              const endFor = (bd: number): Date => {
                if (bd <= 0) return new Date(adjustedStart);
                return calcMethod === '内部'
                  ? addInternalBusinessTime(new Date(adjustedStart), bd, weekendDays, excludedDates)
                  : addBusinessDaysWithHolidays(new Date(adjustedStart), bd, weekendDays, excludedDates);
              };

              let lo = 0;
              let hi = Math.max(1, approxNatural + 50);
              for (let it = 0; it < 40; it++) {
                const mid = (lo + hi) / 2;
                const end = endFor(mid);
                if (end.getTime() < targetDate.getTime()) {
                  lo = mid;
                } else {
                  hi = mid;
                }
              }
              const desiredBusinessDays = Math.round(hi * 2) / 2; // 与UI保持0.5粒度一致

              // 目标调整量 = 目标工作日数 - 基准时效值
              const baseValue = (typeof currentResult.timelineValue === 'number')
                ? currentResult.timelineValue
                : (typeof currentResult.adjustedTimelineValue === 'number')
                  ? currentResult.adjustedTimelineValue
                  : 0;

              const desiredAdjustmentAbs = desiredBusinessDays - baseValue;
              const currentAdj = timelineAdjustments[index] || 0;
              const deltaToApply = desiredAdjustmentAbs - currentAdj;
              if (deltaToApply !== 0) {
                const updated = handleTimelineAdjustment(index, deltaToApply);
                if (!updated) {
                  // 如果该节点不允许调整，仍然重算以联动后续节点
                  setTimeout(() => {
                    recalculateTimeline(timelineAdjustments, false);
                  }, 0);
                  return;
                }
              }
            }
          }
        } catch (e) {
          console.warn('自动调整量计算失败:', e);
        }

        // 无论如何都重新计算时间线以联动交期余量
        setTimeout(() => {
          recalculateTimeline(timelineAdjustments, false);
        }, 0);
      }}
      style={{ width: '140px' }}
      format="yyyy-MM-dd"
    />
  </div>
</div>
                    
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr', gap: '12px', marginTop: '40px' }}>
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>时效值调整：</Text>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, -0.5)}
                        disabled={adjustedValue <= 0 || isCurrentTurnoverZero}
                        style={{ minWidth: '28px', height: '24px', fontSize: '13px' }}
                        title={isCurrentTurnoverZero ? '周转周期为零，无法调整' : ''}
                      >
                        -0.5
                      </Button>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, -1)}
                        disabled={adjustedValue <= 0 || isCurrentTurnoverZero}
                        style={{ minWidth: '24px', height: '24px', fontSize: '13px' }}
                        title={isCurrentTurnoverZero ? '周转周期为零，无法调整' : ''}
                      >
                        -1
                      </Button>
                      <div style={{ 
                        minWidth: '70px', 
                        textAlign: 'center',
                        padding: '2px 6px',
                        border: '1px solid #d9d9d9',
                        borderRadius: '4px',
                        backgroundColor: adjustment !== 0 ? '#fff7e6' : '#f5f5f5',
                        fontSize: '13px'
                      }}>
                        <Text style={{ 
                          color: adjustedValue > 0 ? '#52c41a' : '#ff4d4f',
                          fontWeight: 'bold',
                          fontSize: '13px'
                        }}>
                          {adjustedValue.toFixed(1)} 工作日
                        </Text>
                        {adjustment !== 0 && (
                          <div style={{ fontSize: '10px', color: '#666', lineHeight: '1.2' }}>
                            原值: {baseValue.toFixed(1)}
                            <br />
                            调整: {adjustment > 0 ? '+' : ''}{adjustment.toFixed(1)}
                          </div>
                        )}
                      </div>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, 1)}
                        disabled={isCurrentTurnoverZero || (hasTurnoverNodeWithZero && !isTurnoverNode) || (isTurnoverNode && !isCurrentTurnoverZero) || hasNegativeBuffer}
                        style={{ minWidth: '24px', height: '24px', fontSize: '13px' }}
                        title={
                          isCurrentTurnoverZero ? '周转周期为零，无法调整' : 
                          (hasTurnoverNodeWithZero && !isTurnoverNode) ? '周转周期为零，其他节点无法增加' : 
                          (isTurnoverNode && !isCurrentTurnoverZero) ? '周转周期节点会自动调整，无法手动修改' : 
                          hasNegativeBuffer ? `缓冲期已耗尽且交期余量不足，不允许增加时效` : ''
                        }
                      >
                        +1
                      </Button>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, 0.5)}
                        disabled={isCurrentTurnoverZero || (hasTurnoverNodeWithZero && !isTurnoverNode) || (isTurnoverNode && !isCurrentTurnoverZero) || hasNegativeBuffer}
                        style={{ minWidth: '28px', height: '24px', fontSize: '13px' }}
                        title={
                          isCurrentTurnoverZero ? '周转周期为零，无法调整' : 
                          (hasTurnoverNodeWithZero && !isTurnoverNode) ? '周转周期为零，其他节点无法增加' : 
                          (isTurnoverNode && !isCurrentTurnoverZero) ? '周转周期节点会自动调整，无法手动修改' : 
                          hasNegativeBuffer ? `缓冲期已耗尽且交期余量不足，不允许增加时效` : ''
                        }
                      >
                        +0.5
                      </Button>
                    </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>预计开始：</Text>
                        <Text style={{ fontSize: '14px' }}>{formatDate(result.estimatedStart)}</Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
          <Text>{getDayOfWeek(result.estimatedStart)}</Text>
        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>预计完成：</Text>
                        <Text style={{ 
                          color: result.estimatedEnd.includes('未找到') || result.estimatedEnd.includes('时效值为0') ? '#ff4d4f' : '#52c41a',
                          fontSize: '14px'
                        }}>
                          {result.estimatedEnd === '时效值为0' ? result.estimatedEnd : formatDate(result.estimatedEnd)}
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
          <Text>{getDayOfWeek(result.estimatedEnd)}</Text>
        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>实际跨度：</Text>
                        <Text style={{ color: '#1890ff', fontSize: '14px' }}>
                          {calculateActualDays(result.estimatedStart, result.estimatedEnd)} 自然日
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
                          <Text>含 {adjustedValue.toFixed(1)} 工作日</Text>
                        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>计算方式：</Text>
                        <Text style={{ 
                          color: result.calculationMethod === '内部' ? '#1890ff' : '#52c41a',
                          fontSize: '14px'
                        }}>
                          {result.calculationMethod || '外部'}
                          {result.ruleDescription && (
                            <span style={{ 
                              marginLeft: '8px', 
                              color: '#ff7a00',
                              fontSize: '12px',
                              fontStyle: 'italic'
                            }}>
                              ({result.ruleDescription})
                            </span>
                          )}
                          <span 
                            style={{ 
                              marginLeft: '4px', 
                              cursor: 'help',
                              color: '#666',
                              fontSize: '12px',
                              display: 'inline-flex',
                              alignItems: 'center',
                              justifyContent: 'center',
                              width: '14px',
                              height: '14px',
                              borderRadius: '50%',
                              backgroundColor: '#f0f0f0',
                              border: '1px solid #d9d9d9'
                            }}
                            title={`计算方式详情：\n${result.calculationMethod === '内部' ? '内部计算 (9小时工作制)' : '外部计算 (24小时制)'}${result.ruleDescription ? `\n应用规则：${result.ruleDescription}` : ''}\n已跳过周末：${result.skippedWeekends || 0} 天\n${result.weekendDaysConfig && result.weekendDaysConfig.length > 0 ? `休息日配置：${result.weekendDaysConfig.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(', ')}` : '休息日配置：无固定休息日'}${result.calculationMethod === '内部' ? '\n工作时间：9:00-18:00 (9小时制)' : ''}${(Array.isArray(result.actualExcludedDates) && result.actualExcludedDates.length > 0) ? `\n\n跳过的具体日期：\n${result.actualExcludedDates.join('\n')}` : ''}`}
                          >
                            ?
                          </span>
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '2px' }}>
                          <Text>跳过日期：{(result.actualExcludedDatesCount && result.actualExcludedDatesCount > 0) ? `${result.actualExcludedDatesCount} 天` : '无'}</Text>
                        </div>
                      </div>
                    </div>
                  </Card>
                );
              })}
              
              {/* 计算公式展示卡片 */}
              {timelineResults.length > 0 && (
                <Card style={{ 
                  marginBottom: '16px', 
                  padding: '16px', 
                  background: 'linear-gradient(135deg, #e6f7ff 0%, #f0f9ff 100%)',
                  border: '2px solid #1890ff',
                  borderRadius: '12px',
                  boxShadow: '0 4px 12px rgba(24, 144, 255, 0.15)'
                }}>
                  <div style={{ textAlign: 'center' }}>
                    <Title heading={5} style={{ 
                      margin: '0 0 16px 0', 
                      color: '#1890ff',
                      fontSize: '20px',
                      fontWeight: 'bold'
                    }}>
                      📅 交期余量计算
                    </Title>
                    
                    <div style={{ 
                      display: 'grid', 
                      gridTemplateColumns: expectedDate ? '1fr auto 1fr auto 1fr auto 1fr auto 1fr' : '1fr auto 1fr auto 1fr auto 1fr', 
                      alignItems: 'center', 
                      gap: '12px',
                      marginBottom: '16px',
                      padding: '16px',
                      backgroundColor: 'rgba(255, 255, 255, 0.8)',
                      borderRadius: '8px',
                      border: '1px solid rgba(24, 144, 255, 0.2)'
                    }}>
                      {(() => {
                        // 获取有效的最后流程完成日期
                        let effectiveLastProcess = null;
                        let lastCompletionDate = null;
                        
                        // 从后往前查找第一个有效的流程完成日期
                        for (let i = timelineResults.length - 1; i >= 0; i--) {
                          const process = timelineResults[i];
                          const processDate = new Date(process.estimatedEnd);
                          
                          // 检查日期是否有效且不是"时效值为0"的情况
                          if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                            effectiveLastProcess = process;
                            lastCompletionDate = processDate;
                            break;
                          }
                        }
                        
                        // 如果没有找到有效的完成日期，使用最后一个流程
                        if (!effectiveLastProcess) {
                          effectiveLastProcess = timelineResults[timelineResults.length - 1];
                          lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                        }
                        
                        // 计算所有节点的总调整量（用于动态缓冲期计算）
                        const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
                        
                        // 计算动态缓冲期：基础14天 - 节点总调整量，最小为0天
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                        
                        // 计算最后完成日期 + 动态缓冲期（考虑最后流程完成日期的调整）
                        const adjustedCompletionDate = new Date(lastCompletionDate);
                        adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                        
                        const deliveryDate = new Date(adjustedCompletionDate);
                        deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
                        
                        // 计算交期余量
                        // 如果客户期望日期不为空：交期余量 = 客户期望日期 - (最后流程完成 + 缓冲期)
                        // 如果客户期望日期为空：交期余量 = (最后流程完成 + 缓冲期)
                        let timeDiff, baseDaysDiff, finalDaysDiff;
                        if (expectedDate) {
                          // 有客户期望日期：计算期望日期与交付日期的差值
                          timeDiff = expectedDate.getTime() - deliveryDate.getTime();
                          baseDaysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                        } else {
                          // 无客户期望日期：直接显示交付日期（最后流程完成 + 缓冲期）
                          const today = new Date();
                          today.setHours(0, 0, 0, 0);
                          timeDiff = deliveryDate.getTime() - today.getTime();
                          baseDaysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                        }
                        
                        // 计算最终交期余量：基础余量 - 扣减天数
                        finalDaysDiff = baseDaysDiff - deliveryMarginDeductions;
                        
                        return (
                          <>
                            {expectedDate && (
                              <>
                                {/* 客户期望日期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    客户期望日期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#722ed1',
                                    display: 'block'
                                  }}>
                                    {formatDate(expectedDate)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(expectedDate)}
                                  </Text>
                                </div>
                                
                                {/* 减号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  -
                                </div>
                                
                                {/* 最后流程完成 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    {effectiveLastProcess === timelineResults[timelineResults.length - 1] 
                                      ? '最后流程完成' 
                                      : `有效流程完成 (${effectiveLastProcess.nodeName})`}
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#52c41a',
                                    display: 'block'
                                  }}>
                                    {formatDate(adjustedCompletionDate)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(adjustedCompletionDate)}
                                  </Text>
                                  {effectiveLastProcess !== timelineResults[timelineResults.length - 1] && (
                                    <Text style={{ fontSize: '11px', color: '#fa8c16', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (最后流程时效为0，使用此流程)
                                    </Text>
                                  )}
                                  {completionDateAdjustment > 0 && (
                                    <Text style={{ fontSize: '11px', color: '#1890ff', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (已调整 +{completionDateAdjustment}天)
                                    </Text>
                                  )}
                                </div>
                                
                                {/* 加号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  +
                                </div>
                                
                                {/* 缓冲期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    缓冲期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '20px', 
                                    fontWeight: 'bold',
                                    color: dynamicBufferDays < baseBufferDays ? '#ff4d4f' : '#fa8c16',
                                    display: 'block'
                                  }}>
                                    {dynamicBufferDays}天
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    固定缓冲
                                  </Text>
                                </div>

                                
                                
                                {/* 等号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  =
                                </div>
                              </>
                            )}
                            
                            {!expectedDate && (
                              <>
                                {/* 最后流程完成 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    {effectiveLastProcess === timelineResults[timelineResults.length - 1] 
                                      ? '最后流程完成' 
                                      : `有效流程完成 (${effectiveLastProcess.nodeName})`}
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#52c41a',
                                    display: 'block'
                                  }}>
                                    {formatDate(effectiveLastProcess.estimatedEnd)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(effectiveLastProcess.estimatedEnd)}
                                  </Text>
                                  {effectiveLastProcess !== timelineResults[timelineResults.length - 1] && (
                                    <Text style={{ fontSize: '11px', color: '#fa8c16', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (最后流程时效为0，使用此流程)
                                    </Text>
                                  )}
                                </div>
                                
                                {/* 加号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  +
                                </div>
                                
                                {/* 缓冲期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    缓冲期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '20px', 
                                    fontWeight: 'bold',
                                    color: dynamicBufferDays < baseBufferDays ? '#ff4d4f' : '#fa8c16',
                                    display: 'block'
                                  }}>
                                    {dynamicBufferDays}天
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    固定缓冲
                                  </Text>
                                </div>

                                
                                
                                {/* 减号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  -
                                </div>
                                
                                {/* 今天 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    今天
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#666',
                                    display: 'block'
                                  }}>
                                    {formatDate(new Date())}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(new Date())}
                                  </Text>
                                </div>
                                
                                {/* 等号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  =
                                </div>
                              </>
                            )}
                            
                            {/* 结果日期说明（位于等式下方） */}
                            <div style={{textAlign:'center', marginTop:'8px'}}>
                              <Text style={{ fontSize: '12px', color: '#999' }}>
                                结果日期（最后流程完成 + 缓冲期）：{formatDate(deliveryDate)}，{getDayOfWeek(deliveryDate)}
                              </Text>
                            </div>

                            {/* 交期余量结果 */}
                            <div style={{ 
                              textAlign: 'center',
                              padding: '12px',
                              backgroundColor: finalDaysDiff >= 0 ? '#f6ffed' : '#fff2f0',
                              borderRadius: '8px',
                              border: `2px solid ${finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f'}`
                            }}>
                              <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                交期余量
                              </Text>
                              <Text style={{ 
                                fontSize: '24px', 
                                fontWeight: 'bold',
                                color: finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f',
                                display: 'block'
                              }}>
                                {finalDaysDiff >= 0 ? '+' : ''}{finalDaysDiff}天
                              </Text>
                              <Text style={{ 
                                fontSize: '12px', 
                                color: finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f',
                                fontWeight: 'bold'
                              }}>
                                {finalDaysDiff >= 0 ? '✅ 时间充裕' : '⚠️ 时间紧张'}
                              </Text>
                            </div>
                          </>
                        );
                      })()}
                    </div>
                    
                    <div style={{ 
                      padding: '12px',
                      backgroundColor: 'rgba(255, 255, 255, 0.6)',
                      borderRadius: '6px',
                      fontSize: '13px',
                      color: '#666',
                      lineHeight: '1.5'
                    }}>
                      {(() => {
                        // 计算动态缓冲期和总调整量
                        const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
                        const baseBuferDays = baseBufferDays;
                        const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                        
                        return (
                          <Text>
                            💡 <strong>说明：</strong>
                            {expectedDate 
                              ? `交期余量 = 客户期望日期 - (最后流程完成日期 + ${dynamicBufferDays}天缓冲期)`
                              : `交期余量 = (最后流程完成日期 + ${dynamicBufferDays}天缓冲期) - 今天`
                            }
                            <br />
                            {expectedDate 
                              ? '• 正值表示有充裕时间，负值表示可能延期'
                              : '• 显示预计交付日期距离今天的天数'
                            }
                            <br />
                            • 缓冲期 = 基础{baseBuferDays}天 - 节点调整总量（最小0天），包含质检、包装、物流等后续环节
                            {totalAdjustments > 0 && (
                              <>
                                <br />
                                • 当前节点总调整量：+{totalAdjustments}天，缓冲期相应减少
                              </>
                            )}
                          </Text>
                        );
                      })()}
                    </div>
                  </div>
                </Card>
              )}
              
              <div style={{ marginTop: '16px', padding: '12px', backgroundColor: '#f6f8fa', borderRadius: '6px' }}>
              <Text strong>📊 计算说明：</Text>
                <Text style={{ display: 'block', marginTop: '4px' }}>
                  共找到 {timelineResults.length} 个匹配的节点。时间按流程顺序计算，上一个节点的完成时间等于下一个节点的开始时间。每个节点使用其特定的休息日配置和计算方式进行工作日计算。
                </Text>
                <div style={{ marginTop: '8px', padding: '8px', backgroundColor: '#e6f7ff', borderRadius: '4px' }}>
                  <Text strong style={{ color: '#1890ff' }}>🗓️ 计算规则说明：</Text>
                  <Text style={{ display: 'block', marginTop: '4px', fontSize: '14px' }}>
                    • <strong>内部计算</strong>：按9小时工作制（9:00-18:00），超时自动顺延至下个工作日
                    <br />
                    • <strong>外部计算</strong>：按24小时制计算，适用于外部供应商等不受工作时间限制的节点
                    <br />
                    • 根据每个节点的休息日配置自动跳过相应的休息日
                    <br />
                    • 可为每个节点配置“跳过日期”，这些日期将不参与工作日计算
                    <br />
                    • 时效值以"工作日"为单位计算，确保预期时间的准确性
                    <br />
                    • 使用 +1/-1 按钮调整整天，+0.5/-0.5 按钮调整半天，系统会自动重新计算所有后续节点
                    <br />
                    • 不同节点可配置不同的休息日和计算方式（如：内部节点按工作时间，外部节点按自然时间）
                  </Text>
                </div>
                {Object.keys(timelineAdjustments).length > 0 && (
                  <div style={{ marginTop: '8px', padding: '8px', backgroundColor: '#fff7e6', borderRadius: '4px' }}>
                    <Text strong style={{ color: '#fa8c16' }}>当前调整：</Text>
                    <div style={{ marginTop: '4px' }}>
                      {Object.entries(timelineAdjustments).map(([nodeIndex, adjustment]) => {
                        const nodeName = timelineResults[parseInt(nodeIndex)]?.nodeName;
                        return (
                          <Text key={nodeIndex} style={{ display: 'block', fontSize: '12px' }}>
                            {nodeName}: {adjustment > 0 ? '+' : ''}{adjustment.toFixed(1)} 天
                          </Text>
                        );
                      })}
                    </div>
                  </div>
                )}
              </div>
            </div>
          )}
        </div>
      </Modal>
      

      
      {/* 标签选择部分，仅在生成模式显示 */}
      {mode === 'generate' && labelOptions && Object.keys(labelOptions).length > 0 && (
        <Card title="标签选择" className="card-enhanced" style={{ marginBottom: '24px' }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '16px' }}>
            {Array.from({ length: 10 }, (_, i) => i + 1).map(num => {
              const labelKey = `标签${num}`;
              const options = labelOptions[labelKey] || [];
              const isMultiSelect = labelKey === '标签7' || labelKey === '标签8' || labelKey === '标签10';
              
              return (
                <div key={labelKey}>
                  <Text strong style={{ display: 'block', marginBottom: '8px' }}>{labelKey}</Text>
                  <Select
                    className="select-enhanced"
                    style={{ width: '100%' }}
                    placeholder={`请选择${labelKey}或输入关键字搜索`}
                    value={selectedLabels[labelKey]}
                    onChange={(value) => handleLabelChange(labelKey, value)}
                    multiple={isMultiSelect}
                    filter
                    showSearch
                  >
                    {options.map((option, optionIndex) => (
                      <Select.Option key={optionIndex} value={option.value}>
                        {option.label}
                      </Select.Option>
                    ))}
                  </Select>
                </div>
              );
            })}
          </div>
          
          {/* 客户期望日期选择 */}
          <div style={{ marginTop: '24px' }}>
            <Text strong style={{ display: 'block', marginBottom: '8px' }}>客户期望日期</Text>
            <DatePicker
              className="input-enhanced"
              style={{ width: '300px' }}
              placeholder="请选择客户期望日期"
              value={expectedDate}
              onChange={(date) => setExpectedDate(date)}
              format="yyyy-MM-dd"
              disabledDate={(date) => {
                // 禁用今天之前的日期
                const today = new Date();
                today.setHours(0, 0, 0, 0);
                return date < today;
              }}
            />
            {expectedDate && (
              <Text type="secondary" style={{ marginLeft: '12px' }}>
                已选择：{formatDate(expectedDate, 'CHINESE_DATE')}
              </Text>
            )}
          </div>
          
          {Object.keys(selectedLabels).length > 0 && (
            <div style={{ 
              marginTop: '24px', 
              padding: '20px',
              background: 'linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%)',
              borderRadius: '12px',
              border: '1px solid #bae6fd'
            }}>
              <Space direction="vertical" size="large" style={{ width: '100%' }}>
                <Button 
                  type='primary'
                  className="btn-gradient-calculate"
                  size="large"
                  onClick={handleCalculateTimeline}
                  loading={timelineLoading}
                  disabled={timelineLoading}
                  style={{ minWidth: '160px' }}
                >
                  计算预计时间
                </Button>
                <Text type="secondary" style={{ fontSize: '14px' }}>
                  已选择 {Object.keys(selectedLabels).length} 个标签
                </Text>
              </Space>
              
              <div style={{ marginTop: '16px' }}>
                <Text strong style={{ color: '#0369a1' }}>当前选择的标签：</Text>
                <div style={{ marginTop: '8px', display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
                  {Object.entries(selectedLabels).map(([key, value]) => {
                    const displayValue = Array.isArray(value) ? value.join(', ') : value;
                    return (
                      <span 
                        key={key}
                        style={{
                          background: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)',
                          color: 'white',
                          padding: '4px 12px',
                          borderRadius: '20px',
                          fontSize: '12px',
                          fontWeight: 500
                        }}
                      >
                        {key}: {displayValue}
                      </span>
                    );
                  })}
                </div>
              </div>
            </div>
          )}
        </Card>
      )}

      {mode === 'batch' && (
        <main className="main" style={{ padding: '20px' }}>
          {/* 批量处理配置 */}
          <div className="batch-config-card" style={{ 
              background: 'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)', 
              padding: '24px', 
              borderRadius: '16px', 
              border: '1px solid #e2e8f0',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.05)',
              marginTop: '16px'
            }}>
              <Title heading={4} style={{ marginBottom: '20px', color: '#334155' }}>
                批量处理配置
              </Title>
              <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
                {/* 第一行：表和视图选择 */}
                <div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>数据表:</Text>
                    <Select
                      value={selectedBatchTableId}
                      onChange={handleBatchTableChange}
                      placeholder="请选择表"
                      loading={tablesLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                    >
                      {availableTables.map(table => (
                        <Select.Option key={table.id} value={table.id}>
                          {table.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>视图:</Text>
                    <Select
                      value={selectedBatchViewId}
                      onChange={(value) => setSelectedBatchViewId(value)}
                      placeholder="请选择视图（可选）"
                      loading={viewsLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                      allowClear
                    >
                      {availableViews.map(view => (
                        <Select.Option key={view.id} value={view.id}>
                          {view.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                </div>
                
                {/* 第二行：处理行数和操作按钮 */}
                <div style={{ display: 'flex', gap: '20px', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569' }}>处理行数:</Text>
                    <InputNumber 
                      value={batchRowCount} 
                      onChange={(value) => setBatchRowCount(value || 10)}
                      min={1}
                      max={100}
                      style={{ width: 100 }}
                    />
                  </div>
                  
                  <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                    {batchProcessing && (
                      <div style={{ 
                        display: 'flex', 
                        alignItems: 'center', 
                        gap: '8px',
                        background: 'rgba(59, 130, 246, 0.1)',
                        padding: '8px 16px',
                        borderRadius: '8px',
                        border: '1px solid rgba(59, 130, 246, 0.2)'
                      }}>
                        <div style={{
                          width: '12px',
                          height: '12px',
                          borderRadius: '50%',
                          background: 'conic-gradient(from 0deg, #3b82f6, transparent)',
                          animation: 'spin 1s linear infinite'
                        }}></div>
                        <Text style={{ color: '#3b82f6', fontWeight: 500 }}>
                          进度: {batchProgress.current}/{batchProgress.total}
                        </Text>
                      </div>
                    )}
                    <Button 
                      type="primary" 
                      theme="solid"
                      size="large"
                      loading={batchProcessing}
                      onClick={() => handleBatchProcess(batchRowCount)}
                      disabled={batchProcessing || !selectedBatchTableId}
                      style={{
                        background: selectedBatchTableId ? 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' : undefined,
                        border: 'none',
                        borderRadius: '12px',
                        padding: '12px 24px',
                        fontWeight: 600,
                        boxShadow: selectedBatchTableId ? '0 4px 12px rgba(59, 130, 246, 0.3)' : undefined
                      }}
                    >
                      {batchProcessing ? '批量处理中...' : '开始批量生成'}
                    </Button>
                  </div>
                </div>
              </div>
            </div>
        </main>
      )}
      
      {mode === 'generate' && (
        <main className="main" style={{ padding: '20px' }}>
          <Card className="card-enhanced">
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '24px' }}>
              <div>
                <Title heading={3} style={{ 
                  margin: 0,
                  background: 'linear-gradient(135deg, #1890ff 0%, #722ed1 100%)',
                  WebkitBackgroundClip: 'text',
                  WebkitTextFillColor: 'transparent',
                  backgroundClip: 'text'
                }}>版单数据</Title>
                <Text type='secondary' style={{ fontSize: '14px', marginTop: '4px' }}>
                  选择需要生成时效的版单记录
                </Text>
                {selectedRecords.length > 0 && (
                  <Text type='secondary' style={{ fontSize: '12px', marginTop: '4px' }}>
                    已选择 {selectedRecords.length} 条记录
                  </Text>
                )}
              </div>
              
              <Space>
                <Button 
                  type='primary' 
                  className="btn-gradient-select"
                  size="large"
                  onClick={handleSelectRecords}
                  loading={loading}
                  disabled={loading}
                >
                  {selectedRecords.length > 0 ? '重新选择' : '选择记录'}
                </Button>
                
                {selectedRecords.length > 0 && (
                  <Button 
                    type='secondary' 
                    onClick={handleClearRecords}
                    size='small'
                  >
                    清空选择
                  </Button>
                )}
              </Space>
            </div>
            
            {/* 已选择记录的详细信息 */}
            {selectedRecords.length > 0 && recordDetails.length > 0 && (
              <div style={{ 
                padding: '16px', 
                background: 'linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%)', 
                borderRadius: '12px',
                border: '1px solid #dee2e6',
                marginBottom: '20px',
                boxShadow: '0 2px 8px rgba(0,0,0,0.06)'
              }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
                  <div>
                    <Text strong style={{ color: '#495057' }}>主记录:</Text>
                    <span style={{ 
                      marginLeft: '8px', 
                      fontSize: '12px',
                      background: 'linear-gradient(135deg, #007bff 0%, #0056b3 100%)',
                      color: 'white',
                      padding: '2px 8px',
                      borderRadius: '12px',
                      fontWeight: 500
                    }}>
                      {recordDetails[0].displayValue || recordDetails[0].id}
                    </span>
                  </div>
                  {recordDetails.length > 1 && (
                    <div>
                      <Text type='secondary'>+ 其他 {recordDetails.length - 1} 条</Text>
                    </div>
                  )}
                </div>
              </div>
            )}
            
            {/* 加载状态 */}
            {loading && (
              <div style={{ textAlign: 'center', padding: '20px' }}>
                <Spin size="large" />
                <div style={{ marginTop: '10px' }}>
                  <Text>正在加载版单数据...</Text>
                </div>
              </div>
            )}
            
            {/* 空状态提示 */}
            {selectedRecords.length === 0 && !loading && (
              <div style={{ 
                textAlign: 'center', 
                padding: '20px', 
                backgroundColor: '#fafafa',
                borderRadius: '6px',
                border: '1px dashed #d9d9d9'
              }}>
                <Text type="tertiary">请选择版单记录开始操作</Text>
              </div>
            )}
          </Card>
          
          {/* 批量处理配置 - 移动到版单数据下方 */}
          {mode === 'batch' && (
            <div className="batch-config-card" style={{ 
              background: 'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)', 
              padding: '24px', 
              borderRadius: '16px', 
              border: '1px solid #e2e8f0',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.05)',
              marginTop: '16px'
            }}>
              <Title heading={4} style={{ marginBottom: '20px', color: '#334155' }}>
                批量处理配置
              </Title>
              <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
                {/* 第一行：表和视图选择 */}
                <div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>数据表:</Text>
                    <Select
                      value={selectedBatchTableId}
                      onChange={handleBatchTableChange}
                      placeholder="请选择表"
                      loading={tablesLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                    >
                      {availableTables.map(table => (
                        <Select.Option key={table.id} value={table.id}>
                          {table.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>视图:</Text>
                    <Select
                      value={selectedBatchViewId}
                      onChange={(value) => setSelectedBatchViewId(value)}
                      placeholder="请选择视图（可选）"
                      loading={viewsLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                      allowClear
                    >
                      {availableViews.map(view => (
                        <Select.Option key={view.id} value={view.id}>
                          {view.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                </div>
                
                {/* 第二行：处理行数和操作按钮 */}
                <div style={{ display: 'flex', gap: '20px', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569' }}>处理行数:</Text>
                    <InputNumber 
                      value={batchRowCount} 
                      onChange={(value) => setBatchRowCount(value || 10)}
                      min={1}
                      max={100}
                      style={{ width: 100 }}
                    />
                  </div>
                  
                  <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                    {batchProcessing && (
                      <div style={{ 
                        display: 'flex', 
                        alignItems: 'center', 
                        gap: '8px',
                        background: 'rgba(59, 130, 246, 0.1)',
                        padding: '8px 16px',
                        borderRadius: '8px',
                        border: '1px solid rgba(59, 130, 246, 0.2)'
                      }}>
                        <div style={{
                          width: '12px',
                          height: '12px',
                          borderRadius: '50%',
                          background: 'conic-gradient(from 0deg, #3b82f6, transparent)',
                          animation: 'spin 1s linear infinite'
                        }}></div>
                        <Text style={{ color: '#3b82f6', fontWeight: 500 }}>
                          进度: {batchProgress.current}/{batchProgress.total}
                        </Text>
                      </div>
                    )}
                    <Button 
                      type="primary" 
                      theme="solid"
                      size="large"
                      loading={batchProcessing}
                      onClick={() => handleBatchProcess(batchRowCount)}
                      disabled={batchProcessing || !selectedBatchTableId}
                      style={{
                        background: selectedBatchTableId ? 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' : undefined,
                        border: 'none',
                        borderRadius: '12px',
                        padding: '12px 24px',
                        fontWeight: 600,
                        boxShadow: selectedBatchTableId ? '0 4px 12px rgba(59, 130, 246, 0.3)' : undefined
                      }}
                    >
                      {batchProcessing ? '批量处理中...' : '开始批量生成'}
                    </Button>
                  </div>
                </div>
              </div>
            </div>
          )}
        </main>
      )}
      {mode === 'generate' && (
        <>
          {/* 面料数据查询结果 */}
          {queryResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>面料数据查询结果 ({queryResults.length} 条)</Title>
              <Table 
                columns={columns} 
                dataSource={queryResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
          {/* 二次工艺查询结果 */}
          {secondaryProcessResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>二次工艺查询结果 ({secondaryProcessResults.length} 条)</Title>
              <Table 
                columns={secondaryProcessColumns} 
                dataSource={secondaryProcessResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
          {/* 工艺价格查询结果 */}
          {pricingDetailsResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>工艺价格查询结果 ({pricingDetailsResults.length} 条)</Title>
              <Table 
                columns={pricingDetailsColumns} 
                dataSource={pricingDetailsResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
        </>
      )}
    </div>
  );
}
  DISPLAY_WITH_TIME: 'yyyy-MM-dd HH:mm',           // 显示格式：2026-02-20 16:54
  DISPLAY_DATE_ONLY: 'yyyy-MM-dd',                 // 日期格式：2026-02-20
  STORAGE_FORMAT: 'yyyy-MM-dd HH:mm:ss',           // 存储格式：2026-02-20 16:54:00
  CHINESE_DATE: 'yyyy年MM月dd日',                   // 中文格式：2026年02月20日
} as const;

// 统一的星期显示
const WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] as const;

// 统一的字段提取函数
const extractText = (val: any) => {
  if (Array.isArray(val) && val.length > 0) {
    const item = val[0];
    return typeof item === 'string' ? item : (item?.text || item?.name || '');
  } else if (typeof val === 'string') {
    return val;
  } else if (val && typeof val === 'object') {
    return val.text || val.name || '';
  }
  return '';
};

export default function App() {
  const [selectedRecords, setSelectedRecords] = useState<string[]>([]);
  const [recordDetails, setRecordDetails] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [queryResults, setQueryResults] = useState<any[]>([]);
  const [queryLoading, setQueryLoading] = useState(false);
  const [secondaryProcessResults, setSecondaryProcessResults] = useState<any[]>([]);
  const [secondaryProcessLoading, setSecondaryProcessLoading] = useState(false);
  const [pricingDetailsResults, setPricingDetailsResults] = useState<any[]>([]);
  const [pricingDetailsLoading, setPricingDetailsLoading] = useState(false);
  
  // 标签相关状态
  const [labelOptions, setLabelOptions] = useState<{[key: string]: any[]}>({});
  const [selectedLabels, setSelectedLabels] = useState<{[key: string]: string | string[]}>({});
  const [labelLoading, setLabelLoading] = useState(false);
  
  // 客户期望日期状态
  const [expectedDate, setExpectedDate] = useState<Date | null>(null);
  // 起始时间状态（从货期记录表获取，新记录则使用当前时间）
  const [startTime, setStartTime] = useState<Date | null>(null);
  
  // 预览相关状态（已移除未使用的 previewLoading 状态）
  
  // 时效计算相关状态
  const [timelineVisible, setTimelineVisible] = useState(false);
  const [timelineLoading, setTimelineLoading] = useState(false);
  const [timelineResults, setTimelineResults] = useState<any[]>([]);
  const [timelineAdjustments, setTimelineAdjustments] = useState<{[key: number]: number}>({});
  // 交期余量扣减状态：记录从交期余量中扣减的天数
  const [deliveryMarginDeductions, setDeliveryMarginDeductions] = useState<number>(0);
  // 最后流程完成日期调整状态：记录最后流程完成日期增加的天数
  const [completionDateAdjustment, setCompletionDateAdjustment] = useState<number>(0);
  // 实际完成日期状态：记录每个节点的实际完成日期
  const [actualCompletionDates, setActualCompletionDates] = useState<{[key: number]: Date | null}>({});
  // 基础缓冲期天数（可配置），用于计算动态缓冲期，默认14天
  const [baseBufferDays, setBaseBufferDays] = useState<number>(14);
  // 快照回填来源（foreign_id、款式、颜色、文本2）
  const [currentForeignId, setCurrentForeignId] = useState<string | null>(null);
  const [currentStyleText, setCurrentStyleText] = useState<string>('');
  const [currentColorText, setCurrentColorText] = useState<string>('');
  const [currentText2, setCurrentText2] = useState<string>('');
  const [currentVersionNumber, setCurrentVersionNumber] = useState<number | null>(null);
  // 功能入口模式与调整相关状态
  const [mode, setMode] = useState<'generate' | 'adjust' | null>(null);
  const [modeSelectionVisible, setModeSelectionVisible] = useState(true);
  const [adjustLoading, setAdjustLoading] = useState(false);
  // 删除未使用的 deliveryRecords 状态
  const [selectedDeliveryRecordId, setSelectedDeliveryRecordId] = useState<string>('');
  
  // 批量处理相关状态
  const [batchProcessing, setBatchProcessing] = useState(false);
  const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0 });
  const [batchRowCount, setBatchRowCount] = useState<number>(10); // 默认处理10行
  
  // 批量处理当前记录信息（用于保存时传递正确的数据）
  const [currentBatchRecord, setCurrentBatchRecord] = useState<{
    selectedRecords: string[],
    recordDetails: any[],
    labels: Record<string, any>,
    expectedDate: any,
    startTime: any
  } | null>(null);
  
  // 批量处理表和视图选择状态
  const [selectedBatchTableId, setSelectedBatchTableId] = useState<string>('');
  const [selectedBatchViewId, setSelectedBatchViewId] = useState<string>('');
  const [availableTables, setAvailableTables] = useState<Array<{id: string, name: string}>>([]);
  const [availableViews, setAvailableViews] = useState<Array<{id: string, name: string}>>([]);
  const [tablesLoading, setTablesLoading] = useState(false);
  const [viewsLoading, setViewsLoading] = useState(false);
  
  // 全局变量重置：在切换功能或切换版单/批量数据时，清空页面与计算相关状态
  const resetGlobalState = (opts?: { resetMode?: boolean }) => {
    // 运行时加载状态
    setLoading(false);
    setQueryLoading(false);
    setSecondaryProcessLoading(false);
    setPricingDetailsLoading(false);
    setLabelLoading(false);
    setAdjustLoading(false);
    setTimelineLoading(false);
    setBatchProcessing(false);
    setBatchProgress({ current: 0, total: 0 });

    // 页面与计算数据
    setSelectedRecords([]);
    setRecordDetails([]);
    setSelectedLabels({});
    setExpectedDate(null);
    setStartTime(null);
    setTimelineVisible(false);
    setTimelineResults([]);
    setTimelineAdjustments({});
    setIsRestoringSnapshot(false);

    // 当前记录与批量信息
    setCurrentBatchRecord(null);

    // 当前回填状态
    setCurrentForeignId(null);
    setCurrentStyleText('');
    setCurrentColorText('');
    setCurrentText2('');
    setCurrentVersionNumber(null);

    // 可选：重置模式
    if (opts?.resetMode) {
      setMode(null);
      setModeSelectionVisible(true);
    }
  };

  // 指定的数据表ID和视图ID
  const TABLE_ID = 'tblPIJ7unndydSMu';
  const VIEW_ID = 'vewb28sjuX';

  // 标签表ID
  const LABEL_TABLE_ID = 'tblPnQscqwqopJ8V';

  // 流程配置表ID
  const PROCESS_CONFIG_TABLE_ID = 'tblMygOc6T9o4sYU';
  const NODE_NAME_FIELD_ID = 'fld0g9L9Fw'; // 节点名称字段
  const PROCESS_LABEL_FIELD_ID = 'fldrVTa23X'; // 流程配置表的标签字段
  const PROCESS_ORDER_FIELD_ID = 'fldbfJQ4Zs'; // 流程顺序字段ID
  const WEEKEND_DAYS_FIELD_ID = 'fld2BvjbIN'; // 休息日字段ID（多选项：0-6代表周一到周日）
  const START_DATE_RULE_FIELD_ID = 'fld0KsQ2j3'; // 起始日期调整规则字段ID
  const DATE_ADJUSTMENT_RULE_FIELD_ID = 'fld0KsQ2j3'; // 日期调整规则字段ID
  const EXCLUDED_DATES_FIELD_ID = 'fldGxzC5uG'; // 不参与计算日期（多选，格式：yyyy-MM-dd）
  
  // 时效数据表相关常量
  const TIMELINE_TABLE_ID = 'tblPnQscqwqopJ8V'; // 时效数据表ID
  const TIMELINE_FIELD_ID = 'fldniJmZe3'; // 时效值字段ID
  const TIMELINE_NODE_FIELD_ID = 'fldeIZzokl'; // 时效表中的节点名称字段ID
  const CALCULATION_METHOD_FIELD_ID = 'fldxfLZNUu'; // 时效计算方式字段ID

  // 新表ID（批量生成表）
  const BATCH_TABLE_ID = 'tbl673YuipMIJnXL'; // 新创建的多维表格ID

  // 已移除：调整模式不再加载货期记录列表

  // 入口选择处理
  const chooseMode = (m: 'generate' | 'adjust') => {
    // 切换功能时重置全局变量，但保留新的mode
    resetGlobalState({ resetMode: false });
    setMode(m);
    setModeSelectionVisible(false);
  };

  // 根据货期记录ID读取节点详情并还原流程数据
  const loadProcessDataFromDeliveryRecord = async (deliveryRecordId: string) => {
    if (!deliveryRecordId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'warning', message: '请先选择一条货期记录' });
      }
      return;
    }
    setTimelineLoading(true);
    try {
      const deliveryTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
      const deliveryRecord = await deliveryTable.getRecordById(deliveryRecordId);
      const nodeDetailsVal = deliveryRecord?.fields?.[DELIVERY_NODE_DETAILS_FIELD_ID];

      // 优先使用货期记录表中的快照字段进行一键还原（新方案）
      try {
        const deliverySnapVal = deliveryRecord?.fields?.[DELIVERY_SNAPSHOT_JSON_FIELD_ID];
        let deliverySnapStr: string | null = null;
        if (typeof deliverySnapVal === 'string') {
          deliverySnapStr = deliverySnapVal;
        } else if (Array.isArray(deliverySnapVal)) {
          const texts = deliverySnapVal
            .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
            .map((el: any) => el.text);
          deliverySnapStr = texts.length > 0 ? texts.join('') : null;
        } else if (deliverySnapVal && typeof deliverySnapVal === 'object') {
          if ((deliverySnapVal as any).text && typeof (deliverySnapVal as any).text === 'string') {
            deliverySnapStr = (deliverySnapVal as any).text;
          } else if ((deliverySnapVal as any).type === 'text' && typeof (deliverySnapVal as any).text === 'string') {
            deliverySnapStr = (deliverySnapVal as any).text;
          }
        }

        if (deliverySnapStr && deliverySnapStr.trim() !== '') {
          setIsRestoringSnapshot(true);
          const snapshot = JSON.parse(deliverySnapStr);

          // 恢复页面与全局状态
          if (snapshot.selectedLabels) setSelectedLabels(snapshot.selectedLabels);
          if (!mode && snapshot.mode) setMode(snapshot.mode);
          if (snapshot.foreignId) setCurrentForeignId(snapshot.foreignId);
          if (snapshot.styleText) setCurrentStyleText(snapshot.styleText);
          if (snapshot.colorText) setCurrentColorText(snapshot.colorText);
          if (snapshot.text2) setCurrentText2(snapshot.text2);

          if (snapshot.generationModeState) {
            const genState = snapshot.generationModeState;
            if (genState.currentForeignId) setCurrentForeignId(genState.currentForeignId);
            if (genState.currentStyleText) setCurrentStyleText(genState.currentStyleText);
            if (genState.currentColorText) setCurrentColorText(genState.currentColorText);
            if (genState.currentText2) setCurrentText2(genState.currentText2);
            if (genState.currentVersionNumber !== undefined) setCurrentVersionNumber(genState.currentVersionNumber);
            if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
              setRecordDetails(genState.recordDetails);
            }
          }

          if (snapshot.version !== undefined) {
            let vNum: number | null = null;
            if (typeof snapshot.version === 'number') {
              vNum = snapshot.version;
            } else if (typeof snapshot.version === 'string') {
              const match = snapshot.version.match(/\d+/);
              if (match) vNum = parseInt(match[0], 10);
            }
            if (vNum !== null && !isNaN(vNum)) setCurrentVersionNumber(vNum);
          }

          if (snapshot.timelineAdjustments) setTimelineAdjustments(snapshot.timelineAdjustments);
          if (snapshot.expectedDateTimestamp) {
            setExpectedDate(new Date(snapshot.expectedDateTimestamp));
          } else if (snapshot.expectedDateString) {
            setExpectedDate(new Date(snapshot.expectedDateString));
          }

          // 优先从快照恢复起始时间
          let startTimeRestored = false;
          if (snapshot.startTimestamp) {
            setStartTime(new Date(snapshot.startTimestamp));
            startTimeRestored = true;
          } else if (snapshot.startString) {
            const parsed = new Date(snapshot.startString);
            if (!isNaN(parsed.getTime())) {
              setStartTime(parsed);
              startTimeRestored = true;
            }
          }

          if (!startTimeRestored) {
            const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
            if (startTimeValue) {
              let extractedStartTime: Date | null = null;
              if (typeof startTimeValue === 'number') {
                extractedStartTime = new Date(startTimeValue);
              } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
                const timestamp = startTimeValue[0];
                if (typeof timestamp === 'number') extractedStartTime = new Date(timestamp);
              }
              if (extractedStartTime && !isNaN(extractedStartTime.getTime())) setStartTime(extractedStartTime);
            }
          }

          // 完整快照直接包含timelineResults，优先使用
          if (Array.isArray(snapshot.timelineResults)) {
            setTimelineResults(snapshot.timelineResults);
            setTimelineVisible(true);
            if (bitable.ui.showToast) {
              await bitable.ui.showToast({ toastType: 'success', message: '已按货期记录快照还原流程数据' });
            }
            setTimelineLoading(false);
            setIsRestoringSnapshot(false);
            return;
          }

          // 兼容完整快照标识但没有直接timelineResults的情况
          if (snapshot.isCompleteSnapshot || snapshot.snapshotType === 'complete' || snapshot.isGlobalSnapshot) {
            // 若没有timelineResults，视为旧格式，保持兼容：不在此分支拼装，后续走旧流程
          } else {
            // 非完整快照则进入旧流程（从节点记录扫描快照）
          }
        }
      } catch (e) {
        console.warn('从货期记录快照字段还原失败，回退到旧流程:', e);
      }

      let recordIds: string[] = [];
      if (nodeDetailsVal && typeof nodeDetailsVal === 'object' && (nodeDetailsVal as any).recordIds) {
        recordIds = (nodeDetailsVal as any).recordIds as string[];
      } else if (Array.isArray(nodeDetailsVal)) {
        recordIds = nodeDetailsVal.map((item: any) => item?.recordId || item?.id || item).filter(Boolean);
      }

      if (!recordIds || recordIds.length === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({ toastType: 'warning', message: '该货期记录未包含节点详情或为空' });
        }
        setTimelineLoading(false);
        return;
      }

      const processTable = await bitable.base.getTable(PROCESS_DATA_TABLE_ID);
      const records = await Promise.all(recordIds.map(id => processTable.getRecordById(id)));

      // 优先使用文本2快照一模一样还原
      try {
        // 在所有记录中查找非空快照
        let snapStr: string | null = null;
        for (const rec of records) {
          const snapVal = rec?.fields?.[PROCESS_SNAPSHOT_JSON_FIELD_ID];
          let candidate: string | null = null;
          if (typeof snapVal === 'string') {
            candidate = snapVal;
          } else if (Array.isArray(snapVal)) {
            // 文本结构：拼接所有text片段
            const texts = snapVal
              .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
              .map((el: any) => el.text);
            candidate = texts.length > 0 ? texts.join('') : null;
          } else if (snapVal && typeof snapVal === 'object') {
            // 兼容 {text: '...'} 或 {type:'text', text:'...'}
            if ((snapVal as any).text && typeof (snapVal as any).text === 'string') {
              candidate = (snapVal as any).text;
            } else if ((snapVal as any).type === 'text' && typeof (snapVal as any).text === 'string') {
              candidate = (snapVal as any).text;
            }
          }
          if (candidate && candidate.trim() !== '') {
            snapStr = candidate;
            break;
          }
        }
        if (snapStr && snapStr.trim() !== '') {
          setIsRestoringSnapshot(true); // 开始快照还原
          const snapshot = JSON.parse(snapStr);
          // 恢复页面状态
          if (snapshot.selectedLabels) setSelectedLabels(snapshot.selectedLabels);
          // 保留当前模式，不覆写为快照的模式（避免调整模式被还原为生成模式）
          if (!mode && snapshot.mode) setMode(snapshot.mode);
          // 快照回填的foreign_id/款式/颜色/版本
          if (snapshot.foreignId) setCurrentForeignId(snapshot.foreignId);
          if (snapshot.styleText) setCurrentStyleText(snapshot.styleText);
          if (snapshot.colorText) setCurrentColorText(snapshot.colorText);
          if (snapshot.text2) setCurrentText2(snapshot.text2);
          
          // 恢复生成模式完整状态（如果存在）
          if (snapshot.generationModeState) {
            const genState = snapshot.generationModeState;
            if (genState.currentForeignId) setCurrentForeignId(genState.currentForeignId);
            if (genState.currentStyleText) setCurrentStyleText(genState.currentStyleText);
            if (genState.currentColorText) setCurrentColorText(genState.currentColorText);
            if (genState.currentText2) setCurrentText2(genState.currentText2);
            if (genState.currentVersionNumber !== undefined) setCurrentVersionNumber(genState.currentVersionNumber);
            if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
              // 恢复记录详情（如果需要的话）
              console.log('恢复生成模式记录详情:', genState.recordDetails.length, '条记录');
            }
            console.log('恢复生成模式状态:', {
              hasSelectedLabels: genState.hasSelectedLabels,
              labelSelectionComplete: genState.labelSelectionComplete,
              recordCount: genState.recordDetails?.length || 0
            });
          }
          
          if (snapshot.version !== undefined) {
            let vNum: number | null = null;
            if (typeof snapshot.version === 'number') {
              vNum = snapshot.version;
            } else if (typeof snapshot.version === 'string') {
              const match = snapshot.version.match(/\d+/);
              if (match) {
                vNum = parseInt(match[0], 10);
              }
            }
            if (vNum !== null && !isNaN(vNum)) setCurrentVersionNumber(vNum);
          }
          if (snapshot.timelineAdjustments) setTimelineAdjustments(snapshot.timelineAdjustments);
          if (snapshot.expectedDateTimestamp) {
            setExpectedDate(new Date(snapshot.expectedDateTimestamp));
          } else if (snapshot.expectedDateString) {
            setExpectedDate(new Date(snapshot.expectedDateString));
          }
          
          // 优先从快照恢复起始时间，如果快照中没有则从当前货期记录中获取
          let startTimeRestored = false;
          if (snapshot.startTimestamp) {
            setStartTime(new Date(snapshot.startTimestamp));
            startTimeRestored = true;
          } else if (snapshot.startString) {
            const parsed = new Date(snapshot.startString);
            if (!isNaN(parsed.getTime())) {
              setStartTime(parsed);
              startTimeRestored = true;
            }
          }
          
          // 如果快照中没有起始时间信息，则从当前选中的货期记录中获取
          if (!startTimeRestored) {
            const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
            if (startTimeValue) {
              let extractedStartTime: Date | null = null;
              if (typeof startTimeValue === 'number') {
                extractedStartTime = new Date(startTimeValue);
              } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
                const timestamp = startTimeValue[0];
                if (typeof timestamp === 'number') {
                  extractedStartTime = new Date(timestamp);
                }
              }
              
              if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
                setStartTime(extractedStartTime);
              }
            }
          }
          
          if (Array.isArray(snapshot.timelineResults)) {
            // 兼容旧版本的完整快照格式
            setTimelineResults(snapshot.timelineResults);
            setTimelineVisible(true);
            if (bitable.ui.showToast) {
              await bitable.ui.showToast({ toastType: 'success', message: '已按快照一模一样还原流程数据' });
            }
            setTimelineLoading(false);
            setIsRestoringSnapshot(false); // 快照还原完成
            return; // 快照还原完成，退出函数
          } else if (snapshot.isCompleteSnapshot || snapshot.snapshotType === 'complete' || 
                     snapshot.isGlobalSnapshot || snapshot.isCombinedSnapshot) {
            // 处理完整快照格式：每个节点都包含完整数据
            console.log('检测到完整快照格式，直接使用快照数据');
            
            // 如果是完整快照，直接使用其中的timelineResults
            if (snapshot.isCompleteSnapshot && snapshot.timelineResults) {
              console.log('使用完整快照中的timelineResults数据');
              setTimelineResults(snapshot.timelineResults);
              setTimelineVisible(true);
              
              // 恢复智能缓冲期状态
              if (snapshot.bufferManagement) {
                console.log('恢复智能缓冲期状态:', snapshot.bufferManagement);
              }
              
              // 恢复连锁调整系统状态
              if (snapshot.chainAdjustmentSystem) {
                console.log('恢复连锁调整系统状态:', snapshot.chainAdjustmentSystem);
              }
              
              // 恢复生成模式状态
              if (snapshot.generationModeState) {
                console.log('恢复生成模式状态:', snapshot.generationModeState);
                const genState = snapshot.generationModeState;
                
                // 恢复foreign_id状态
                if (genState.currentForeignId) {
                  setCurrentForeignId(genState.currentForeignId);
                  console.log('恢复foreign_id状态:', genState.currentForeignId);
                }
                
                // 恢复款式和颜色状态
                if (genState.currentStyleText) {
                  setCurrentStyleText(genState.currentStyleText);
                  console.log('恢复款式状态:', genState.currentStyleText);
                }
                if (genState.currentColorText) {
                  setCurrentColorText(genState.currentColorText);
                  console.log('恢复颜色状态:', genState.currentColorText);
                }
                
                // 恢复text2状态
                if (genState.currentText2) {
                  setCurrentText2(genState.currentText2);
                  console.log('恢复text2状态:', genState.currentText2);
                }
                
                // 恢复版本号状态
                if (genState.currentVersionNumber !== undefined) {
                  setCurrentVersionNumber(genState.currentVersionNumber);
                  console.log('恢复版本号状态:', genState.currentVersionNumber);
                }
                
                // 恢复记录详情状态
                if (genState.recordDetails && Array.isArray(genState.recordDetails)) {
                  setRecordDetails(genState.recordDetails);
                  console.log('恢复记录详情状态，记录数量:', genState.recordDetails.length);
                }
              }
              
              // 恢复时间线计算状态
              if (snapshot.timelineCalculationState) {
                console.log('恢复时间线计算状态:', snapshot.timelineCalculationState);
              }
              
              if (bitable.ui.showToast) {
                await bitable.ui.showToast({ 
                  toastType: 'success', 
                  message: '已按完整快照还原流程数据' 
                });
              }
              setTimelineLoading(false);
              setIsRestoringSnapshot(false);
              return;
            }
            
            // 兼容旧版本分散快照格式的处理逻辑
            // 新版本的分散快照格式：需要从所有节点收集数据
            console.log('检测到新版本快照格式，开始收集所有节点的快照数据');
            
            try {
              // 收集所有节点的快照数据
              const nodeSnapshots: any[] = [];
              let globalSnapshotData = snapshot.isCompleteSnapshot ? snapshot : null;
              
              // 遍历所有记录，收集快照数据
              for (const record of records) {
                const fields = record?.fields || {};
                const snapshotField = fields[PROCESS_SNAPSHOT_JSON_FIELD_ID];
                
                if (snapshotField) {
                  let nodeSnapStr = '';
                  
                  // 解析快照字段（支持多种格式）
                  if (typeof snapshotField === 'string') {
                    nodeSnapStr = snapshotField;
                  } else if (Array.isArray(snapshotField)) {
                    const texts = snapshotField
                      .filter((el: any) => el && el.type === 'text' && typeof el.text === 'string')
                      .map((el: any) => el.text);
                    nodeSnapStr = texts.length > 0 ? texts.join('') : '';
                  } else if (snapshotField && typeof snapshotField === 'object') {
                    if ((snapshotField as any).text && typeof (snapshotField as any).text === 'string') {
                      nodeSnapStr = (snapshotField as any).text;
                    }
                  }
                  
                  if (nodeSnapStr && nodeSnapStr.trim() !== '') {
                    try {
                      const nodeSnapshot = JSON.parse(nodeSnapStr);
                      
                      // 批量模式现在使用扁平化结构，直接从快照中提取全局数据
                      if (nodeSnapshot.isCompleteSnapshot && !globalSnapshotData) {
                        globalSnapshotData = {
                          version: nodeSnapshot.version,
                          foreignId: nodeSnapshot.foreignId,
                          styleText: nodeSnapshot.styleText,
                          colorText: nodeSnapshot.colorText,
                          text2: nodeSnapshot.text2,
                          mode: nodeSnapshot.mode,
                          selectedLabels: nodeSnapshot.selectedLabels,
                          expectedDateTimestamp: nodeSnapshot.expectedDateTimestamp,
                          expectedDateString: nodeSnapshot.expectedDateString,
                          startTimestamp: nodeSnapshot.startTimestamp,
                          startString: nodeSnapshot.startString,
                          timelineAdjustments: nodeSnapshot.timelineAdjustments,
                          // 恢复智能缓冲期管理状态
                          bufferManagement: nodeSnapshot.bufferManagement,
                          // 恢复连锁调整系统状态
                          chainAdjustmentSystem: nodeSnapshot.chainAdjustmentSystem,
                          // 恢复生成模式状态
                          generationModeState: nodeSnapshot.generationModeState,
                          // 恢复时间线计算状态
                          timelineCalculationState: nodeSnapshot.timelineCalculationState,
                          totalNodes: nodeSnapshot.totalNodes
                        };
                      }
                      
                      // 扁平化结构中，每个快照都包含完整的节点数据
                      if (nodeSnapshot.isCompleteSnapshot) {
                        // 确保adjustedTimelineValue有正确的默认值
                        const adjustedTimelineValue = nodeSnapshot.adjustedTimelineValue !== undefined ? 
                          nodeSnapshot.adjustedTimelineValue : nodeSnapshot.timelineValue;
                        
                        // 处理日期格式，优先使用时间戳格式
                        let estimatedStart = nodeSnapshot.estimatedStart;
                        let estimatedEnd = nodeSnapshot.estimatedEnd;
                        
                        // 如果有时间戳格式的日期，使用时间戳重新格式化
                        if (nodeSnapshot.estimatedStartTimestamp) {
                          try {
                            estimatedStart = formatDate(new Date(nodeSnapshot.estimatedStartTimestamp));
                          } catch (error) {
                            console.warn('时间戳格式开始时间转换失败:', error);
                          }
                        }
                        
                        if (nodeSnapshot.estimatedEndTimestamp) {
                          try {
                            estimatedEnd = formatDate(new Date(nodeSnapshot.estimatedEndTimestamp));
                          } catch (error) {
                            console.warn('时间戳格式结束时间转换失败:', error);
                          }
                        }
                        
                        // 调试日志
                        console.log(`节点 ${nodeSnapshot.nodeName} 快照还原:`, {
                          timelineValue: nodeSnapshot.timelineValue,
                          adjustedTimelineValue: adjustedTimelineValue,
                          originalAdjustedTimelineValue: nodeSnapshot.adjustedTimelineValue,
                          estimatedStart: estimatedStart,
                          estimatedEnd: estimatedEnd,
                          hasTimestamps: {
                            start: Boolean(nodeSnapshot.estimatedStartTimestamp),
                            end: Boolean(nodeSnapshot.estimatedEndTimestamp)
                          },
                          nodeCalculationState: nodeSnapshot.nodeCalculationState
                        });
                        
                        nodeSnapshots.push({
                          processOrder: nodeSnapshot.processOrder,
                          nodeName: nodeSnapshot.nodeName || nodeSnapshot.currentNodeName,
                          matchedLabels: nodeSnapshot.matchedLabels,
                          timelineValue: nodeSnapshot.timelineValue,
                          estimatedStart: estimatedStart,
                          estimatedEnd: estimatedEnd,
                          timelineRecordId: nodeSnapshot.timelineRecordId,
                          allMatchedRecords: nodeSnapshot.allMatchedRecords,
                          isAccumulated: nodeSnapshot.isAccumulated,
                          weekendDaysConfig: nodeSnapshot.weekendDaysConfig,
                          excludedDates: nodeSnapshot.excludedDates,
                          actualExcludedDates: nodeSnapshot.actualExcludedDates,
                          actualExcludedDatesCount: nodeSnapshot.actualExcludedDatesCount,
                          calculationMethod: nodeSnapshot.calculationMethod,
                          ruleDescription: nodeSnapshot.ruleDescription,
                          skippedWeekends: nodeSnapshot.skippedWeekends,
                          actualDays: nodeSnapshot.actualDays,
                          adjustedTimelineValue: adjustedTimelineValue,
                          adjustment: nodeSnapshot.adjustment || 0,
                          adjustmentDescription: nodeSnapshot.adjustmentDescription || '',
                          startDateRule: nodeSnapshot.startDateRule,
                          dateAdjustmentRule: nodeSnapshot.dateAdjustmentRule,
                          // 恢复节点计算状态
                          nodeCalculationState: nodeSnapshot.nodeCalculationState,
                          // 恢复连锁调整节点状态
                          chainAdjustmentNode: nodeSnapshot.chainAdjustmentNode
                        });
                      }
                    } catch (parseError) {
                      console.warn('解析节点快照失败:', parseError);
                    }
                  }
                }
              }
              
              // 按流程顺序排序节点快照
              nodeSnapshots.sort((a, b) => (a.processOrder || 0) - (b.processOrder || 0));
              
              console.log('收集到的节点快照数量:', nodeSnapshots.length);
              console.log('全局快照数据:', globalSnapshotData);
              
              // 验证数据完整性
              if (globalSnapshotData && globalSnapshotData.totalNodes && 
                  nodeSnapshots.length === globalSnapshotData.totalNodes) {
                
                // 重组完整的 timelineResults
                setTimelineResults(nodeSnapshots);
                setTimelineVisible(true);
                
                // 恢复智能缓冲期状态（如果存在）
                if (globalSnapshotData.bufferManagement) {
                  console.log('恢复智能缓冲期状态:', globalSnapshotData.bufferManagement);
                  // 这里可以添加额外的状态恢复逻辑，如果需要的话
                }
                
                // 恢复连锁调整系统状态（如果存在）
                if (globalSnapshotData.chainAdjustmentSystem) {
                  console.log('恢复连锁调整系统状态:', globalSnapshotData.chainAdjustmentSystem);
                  // 这里可以添加额外的状态恢复逻辑，如果需要的话
                }
                
                // 恢复生成模式状态（如果存在）
                if (globalSnapshotData.generationModeState) {
                  console.log('恢复生成模式状态:', globalSnapshotData.generationModeState);
                  const genState = globalSnapshotData.generationModeState;
                  
                  // 确保生成模式的关键状态被正确恢复
                  if (genState.currentForeignId && !currentForeignId) {
                    setCurrentForeignId(genState.currentForeignId);
                  }
                  if (genState.currentStyleText && !currentStyleText) {
                    setCurrentStyleText(genState.currentStyleText);
                  }
                  if (genState.currentColorText && !currentColorText) {
                    setCurrentColorText(genState.currentColorText);
                  }
                  if (genState.currentText2 && !currentText2) {
                    setCurrentText2(genState.currentText2);
                  }
                  if (genState.currentVersionNumber !== undefined && !currentVersionNumber) {
                    setCurrentVersionNumber(genState.currentVersionNumber);
                  }
                }
                
                // 恢复时间线计算状态（如果存在）
                if (globalSnapshotData.timelineCalculationState) {
                  console.log('恢复时间线计算状态:', globalSnapshotData.timelineCalculationState);
                }

                if (bitable.ui.showToast) {
                  await bitable.ui.showToast({ 
                    toastType: 'success', 
                    message: `已从 ${nodeSnapshots.length} 个节点快照还原完整流程数据（包含智能缓冲期和连锁调整状态）` 
                  });
                }
                setTimelineLoading(false);
                setIsRestoringSnapshot(false); // 快照还原完成
                return; // 快照还原完成，退出函数
              } else {
                console.warn('快照数据不完整，降级为基于字段的还原');
                console.log('期望节点数:', globalSnapshotData?.totalNodes, '实际节点数:', nodeSnapshots.length);
              }
              
            } catch (collectError) {
              console.warn('收集节点快照数据失败，降级为基于字段的还原:', collectError);
            }
          }
        }
      } catch (snapError) {
        console.warn('解析快照失败，降级为基于字段的还原:', snapError);
        setIsRestoringSnapshot(false); // 快照还原失败，重置标志
      }

      // 如果到达这里，说明没有成功的快照还原，重置标志
      setIsRestoringSnapshot(false);

      const results = records.map((rec: any) => {
        const fields = rec?.fields || {};
        const processOrder = fields[PROCESS_ORDER_FIELD_ID_DATA];
        const nodeName = fields[PROCESS_NAME_FIELD_ID];
        const startTs = fields[ESTIMATED_START_DATE_FIELD_ID];
        const endTs = fields[ESTIMATED_END_DATE_FIELD_ID];
        const startDate = typeof startTs === 'number' ? new Date(startTs) : (startTs ? new Date(startTs) : null);
        const endDate = typeof endTs === 'number' ? new Date(endTs) : (endTs ? new Date(endTs) : null);
        return {
          processOrder: typeof processOrder === 'number' ? processOrder : parseInt(processOrder) || undefined,
          nodeName: typeof nodeName === 'string' ? nodeName : (nodeName?.text || ''),
          estimatedStart: startDate ? format(startDate, DATE_FORMATS.STORAGE_FORMAT) : '未找到时效数据',
          estimatedEnd: endDate ? format(endDate, DATE_FORMATS.STORAGE_FORMAT) : '未找到时效数据',
          timelineRecordId: rec?.id || rec?.recordId || null,
          timelineValue: undefined,
          calculationMethod: undefined,
          weekendDaysConfig: [],
          matchedLabels: [],
          skippedWeekends: 0,
          actualDays: undefined,
          startDateRule: undefined,
          dateAdjustmentRule: undefined,
          ruleDescription: undefined,
          adjustmentDescription: undefined
        };
      });

      // 如果没有快照恢复起始时间，则从当前货期记录中获取起始时间
      const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
      if (startTimeValue) {
        let extractedStartTime: Date | null = null;
        if (typeof startTimeValue === 'number') {
          extractedStartTime = new Date(startTimeValue);
        } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
          const timestamp = startTimeValue[0];
          if (typeof timestamp === 'number') {
            extractedStartTime = new Date(timestamp);
          }
        }
        
        if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
          setStartTime(extractedStartTime);
        }
      }

      const sorted = results.sort((a, b) => (a.processOrder || 0) - (b.processOrder || 0));
      setTimelineResults(sorted);
      setTimelineVisible(true);

      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'success', message: '已从货期记录还原流程数据' });
      }
    } catch (error) {
      console.error('从货期记录还原流程数据失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({ toastType: 'error', message: `还原失败: ${(error as Error).message}` });
      }
    } finally {
      setTimelineLoading(false);
    }
  };

  // 流程数据表相关常量
  const PROCESS_DATA_TABLE_ID = 'tblsJzCxXClj5oK5'; // 流程数据表ID
  const FOREIGN_ID_FIELD_ID = 'fld3oxJmpr'; // foreign_id字段
  const PROCESS_NAME_FIELD_ID = 'fldR79qEG3'; // 流程名称字段
  const PROCESS_ORDER_FIELD_ID_DATA = 'fldmND6vjT'; // 流程顺序字段
  const ESTIMATED_START_DATE_FIELD_ID = 'fldlzvHjYP'; // 预计开始日期字段
  const ESTIMATED_END_DATE_FIELD_ID = 'fldaPtY7Jk'; // 预计完成日期字段
  const PROCESS_SNAPSHOT_JSON_FIELD_ID = 'fldSHTxfnC'; // 文本2：用于保存计算页面快照(JSON)
  const PROCESS_VERSION_FIELD_ID = 'fldwk5X7Yw'; // 版本字段
  const PROCESS_TIMELINESS_FIELD_ID = 'fldEYCXnWt'; // 时效字段（天）

  // 货期记录表相关常量
  const DELIVERY_RECORD_TABLE_ID = 'tblwiA49gksQrnfg'; // 货期记录表ID
  const DELIVERY_FOREIGN_ID_FIELD_ID = 'fld0gAIcHS'; // foreign_id字段（需要替换为实际字段ID）
  const DELIVERY_LABELS_FIELD_ID = 'fldp0cDP2T'; // 标签汇总字段（需要替换为实际字段ID）
  const DELIVERY_STYLE_FIELD_ID = 'fldJRFxwB1'; // 款式字段（需要替换为实际字段ID）
  const DELIVERY_COLOR_FIELD_ID = 'fldhA1uBMy'; // 颜色字段（需要替换为实际字段ID）
  const DELIVERY_CREATE_TIME_FIELD_ID = 'fldP4w79LQ'; // 生成时间字段（需要替换为实际字段ID）
  const DELIVERY_EXPECTED_DATE_FIELD_ID = 'fldrjlzsxn'; // 预计交付日期字段（需要替换为实际字段ID）
  const DELIVERY_NODE_DETAILS_FIELD_ID = 'fldu1KL9yC'; // 节点详情字段（需要替换为实际字段ID）
  const DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID = 'fldYNluU8D'; // 客户期望日期字段
  const DELIVERY_ADJUSTMENT_INFO_FIELD_ID = 'fldNc6nNsz'; // 货期调整信息字段（需要替换为实际字段ID）
  const DELIVERY_VERSION_FIELD_ID = 'fld5OmvZrn'; // 版本字段（新增）
  const DELIVERY_SNAPSHOT_JSON_FIELD_ID = 'fldEYIvHeP'; // 货期记录表：完整快照(JSON)
  // 起始时间字段（货期记录表新增）
  const DELIVERY_START_TIME_FIELD_ID = 'fld727qCAv';
  // 文本2字段（货期记录表新增）
  const DELIVERY_TEXT2_FIELD_ID = 'fldG6LZnmU';

  // 已移除中国法定节假日相关常量和配置

  // 这个变量声明也不需要了
  // const nodeNameToOptionId = new Map();

  // 统一的日期格式化函数
  const formatDate = (date: Date | string, formatType: keyof typeof DATE_FORMATS = 'DISPLAY_WITH_TIME'): string => {
    try {
      if (!date) return '';
      
      const dateObj = typeof date === 'string' ? parseDate(date) : date;
      if (!dateObj || isNaN(dateObj.getTime())) {
        return '';
      }
      
      return format(dateObj, DATE_FORMATS[formatType], { locale: zhCN });
    } catch (error) {
      console.error('日期格式化失败:', error, { date, formatType });
      return '';
    }
  };

  // 统一的日期解析函数
  const parseDate = (dateStr: string): Date | null => {
    try {
      if (!dateStr || dateStr.includes('未找到') || dateStr.includes('时效值为0')) {
        return null;
      }
      
      // 如果是时间戳格式，直接转换
      if (/^\d{13}$/.test(dateStr)) {
        const date = new Date(parseInt(dateStr));
        if (!isNaN(date.getTime())) {
          return date;
        }
      }
      
      // 移除所有星期信息（支持"星期X"和"周X"格式）
      let cleanStr = dateStr
        .replace(/\s*星期[一二三四五六日天]\s*/g, ' ')
        .replace(/\s*周[一二三四五六日天]\s*/g, ' ')
        .replace(/\s+/g, ' ')
        .trim();
      
      // 处理可能的格式问题：如果日期和时间连在一起了，添加空格
      cleanStr = cleanStr.replace(/(\d{4}-\d{2}-\d{2})(\d{2}:\d{2})/, '$1 $2');
      
      // 尝试标准解析
      let date = new Date(cleanStr);
      if (!isNaN(date.getTime())) {
        return date;
      }
      
      // 手动解析 "YYYY-MM-DD HH:mm" 或 "YYYY-MM-DD HH:mm:ss" 格式
      const match = cleanStr.match(/(\d{4})-(\d{2})-(\d{2})(?:\s+(\d{2}):(\d{2})(?::(\d{2}))?)?/);
      if (match) {
        const [, year, month, day, hour = '0', minute = '0', second = '0'] = match;
        return new Date(
          parseInt(year), 
          parseInt(month) - 1, 
          parseInt(day), 
          parseInt(hour), 
          parseInt(minute), 
          parseInt(second)
        );
      }
      
      throw new Error(`无法解析日期格式: ${cleanStr}`);
    } catch (error) {
      console.error('日期解析失败:', { dateStr, error: error.message });
      return null;
    }
  };

  // 获取星期几（统一格式）
  const getDayOfWeek = (dateStr: string | Date): string => {
    try {
      const date = typeof dateStr === 'string' ? parseDate(dateStr) : dateStr;
      if (!date || isNaN(date.getTime())) {
        return '';
      }
      return WEEKDAYS[date.getDay()];
    } catch (error) {
      console.error('获取星期失败:', error, { dateStr });
      return '';
    }
  };

  // 重构计算实际跨度天数函数
  const calculateActualDays = (startDateStr: string | Date, endDateStr: string | Date): number => {
    try {
      const startDate = typeof startDateStr === 'string' ? parseDate(startDateStr) : startDateStr;
      const endDate = typeof endDateStr === 'string' ? parseDate(endDateStr) : endDateStr;
      
      if (!startDate || !endDate || isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
        console.log('日期解析失败:', { startDateStr, endDateStr, startDate, endDate });
        return 0;
      }
      
      // 计算日期差异（只考虑日期部分）
      const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
      const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
      
      const diffTime = endDateOnly.getTime() - startDateOnly.getTime();
      const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
      
      console.log('自然日计算:', { 
        startDateStr: formatDate(startDate), 
        endDateStr: formatDate(endDate), 
        diffDays 
      });
      
      return Math.max(0, diffDays);
    } catch (error) {
      console.error('计算自然日出错:', error, { startDateStr, endDateStr });
      return 0;
    }
  };

  // 计算跳过的周末天数 - 支持空的休息日配置
  const calculateSkippedWeekends = (startDate: Date | string, endDate: Date | string, weekendDays: number[] = []): number => {
    if (weekendDays.length === 0) return 0; // 如果没有配置休息日，则不跳过任何天数
    
    try {
      const start = typeof startDate === 'string' ? new Date(startDate) : startDate;
      const end = typeof endDate === 'string' ? new Date(endDate) : endDate;
      
      if (isNaN(start.getTime()) || isNaN(end.getTime())) {
        return 0;
      }
      
      let count = 0;
      const current = new Date(start);
      
      while (current <= end) {
        if (weekendDays.includes(current.getDay())) {
          count++;
        }
        current.setDate(current.getDate() + 1);
      }
      
      return count;
    } catch (error) {
      return 0;
    }
  };

  // 计算时间范围内实际跳过的自定义日期
  const calculateExcludedDatesInRange = (startDate: Date | string, endDate: Date | string, excludedDates: string[] = []): { count: number, dates: string[] } => {
    if (!excludedDates || excludedDates.length === 0) {
      return { count: 0, dates: [] };
    }
    
    try {
      const start = typeof startDate === 'string' ? parseDate(startDate) : startDate;
      const end = typeof endDate === 'string' ? parseDate(endDate) : endDate;
      
      if (!start || !end || isNaN(start.getTime()) || isNaN(end.getTime())) {
        return { count: 0, dates: [] };
      }
      
      const actualExcludedDates: string[] = [];
      
      for (const excludedDateStr of excludedDates) {
        const excludedDate = parseDate(excludedDateStr);
        if (excludedDate && excludedDate >= start && excludedDate <= end) {
          actualExcludedDates.push(excludedDateStr);
        }
      }
      
      return { count: actualExcludedDates.length, dates: actualExcludedDates };
    } catch (error) {
      console.error('计算跳过日期失败:', error);
      return { count: 0, dates: [] };
    }
  };

  // 已移除法定节假日跳过统计函数

  // 已移除中国节假日判断函数

  // 判断是否为自定义周末 - 支持空的休息日配置
  const isCustomWeekend = (date: Date, weekendDays: number[] = []): boolean => {
    if (weekendDays.length === 0) return false; // 如果没有配置休息日，则不认为是周末
    return weekendDays.includes(date.getDay());
  };

  // 判断是否为工作日 - 排除表格休息日、以及节点自定义不参与计算日期
  const isBusinessDay = (date: Date, weekendDays: number[] = [], excludedDates: string[] = []): boolean => {
    try {
      const dateStr = format(date, 'yyyy-MM-dd');
      const isExcluded = Array.isArray(excludedDates) && excludedDates.includes(dateStr);
      return !isCustomWeekend(date, weekendDays) && !isExcluded;
    } catch {
      return !isCustomWeekend(date, weekendDays);
    }
  };

  // 日期调整函数
  const adjustStartDateByRule = (date: Date, ruleJson: string): Date => {
    if (!ruleJson || ruleJson.trim() === '') {
      return date;
    }
    
    try {
      const config = JSON.parse(ruleJson);
      const adjustedDate = new Date(date);
      const currentDayOfWeek = adjustedDate.getDay(); // 0=周日, 1=周一, ..., 6=周六
      
      // 转换为1-7格式（1=周一, 7=周日）
      const dayOfWeek = currentDayOfWeek === 0 ? 7 : currentDayOfWeek;
      
      if (config.rules && Array.isArray(config.rules)) {
        for (const rule of config.rules) {
          if (rule.condition === 'dayOfWeek' && rule.value === dayOfWeek) {
            if (rule.action === 'delayToNextWeek') {
              // 计算下周目标日期
              const targetDay = rule.targetDay || 1; // 默认周一
              const daysToAdd = 7 - dayOfWeek + targetDay;
              adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
              
              console.log(`应用规则: ${rule.description || '未知规则'}, 原日期: ${format(date, 'yyyy-MM-dd')}, 调整后: ${format(adjustedDate, 'yyyy-MM-dd')}`);
              break; // 只应用第一个匹配的规则
            }
          }
        }
      }
      
      return adjustedDate;
    } catch (error) {
      console.error('解析日期调整规则失败:', error);
      return date; // 解析失败时返回原日期
    }
  };

  // JSON格式日期调整函数 - 修改为返回调整结果和描述
  const adjustStartDateByJsonRule = (date: Date, ruleJson: string): { adjustedDate: Date, description?: string } => {
    if (!ruleJson || ruleJson.trim() === '') {
      return { adjustedDate: date };
    }
    
    try {
      const rules = JSON.parse(ruleJson);
      const dayOfWeek = date.getDay(); // 0=周日, 1=周一, ..., 6=周六
      const dayKey = dayOfWeek === 0 ? '7' : dayOfWeek.toString(); // 转换为1-7格式
      
      const rule = rules[dayKey];
      if (!rule) {
        return { adjustedDate: date }; // 没有匹配的规则，返回原日期
      }
      
      const adjustedDate = new Date(date);
      let description = rule.description || '';
      
      switch (rule.action) {
        case 'delayInSameWeek':
          // 在本周内延期到指定星期几
          const targetDay = rule.targetDay;
          const currentDay = dayOfWeek === 0 ? 7 : dayOfWeek; // 转换为1-7格式
          
          if (targetDay > currentDay) {
            // 延期到本周的目标日期
            adjustedDate.setDate(adjustedDate.getDate() + (targetDay - currentDay));
          } else {
            // 如果目标日期已过，延期到下周的目标日期
            adjustedDate.setDate(adjustedDate.getDate() + (7 - currentDay + targetDay));
          }
          break;
          
        case 'delayToNextWeek':
          // 延期到下周的指定星期几
          const nextWeekTargetDay = rule.targetDay;
          const daysToAdd = 7 - (dayOfWeek === 0 ? 7 : dayOfWeek) + nextWeekTargetDay;
          adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
          break;
          
        case 'delayDays':
          // 直接延期指定天数
          const delayDays = rule.days || 0;
          adjustedDate.setDate(adjustedDate.getDate() + delayDays);
          break;
          
        default:
          console.warn(`未知的调整动作: ${rule.action}`);
          break;
      }
      
      console.log(`应用调整规则: ${dayKey} -> ${JSON.stringify(rule)}, 原日期: ${date.toDateString()}, 调整后: ${adjustedDate.toDateString()}`);
      return { adjustedDate, description };
      
    } catch (error) {
      console.error('解析日期调整规则失败:', error, '规则内容:', ruleJson);
      return { adjustedDate: date }; // 解析失败时返回原日期
    }
  };

  // 调整到下一个工作时间开始点
  const adjustToNextWorkingHour = (date: Date, calculationMethod: string, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(date);
    
    if (calculationMethod === '内部') {
      const hour = result.getHours();
      const minute = result.getMinutes();
      
      // 如果是工作时间外（18:00之后或9:00之前），调整到下一个工作日的9:00
      if (hour >= 18 || hour < 9) {
        // 如果是当天18:00之后，调整到下一个工作日
        if (hour >= 18) {
          result.setDate(result.getDate() + 1);
        }
        
        // 找到下一个工作日（考虑休息日和自定义跳过日期）
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        
        // 设置为9:00:00
        result.setHours(9, 0, 0, 0);
      }
    }
    
    return result;
  };

  // 内部工作时间计算函数
  const addInternalBusinessTime = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(startDate);
    let remainingDays = businessDays;
    
    // 处理整数天
    const wholeDays = Math.floor(remainingDays);
    let addedDays = 0;
    
    while (addedDays < wholeDays) {
      result.setDate(result.getDate() + 1);
      if (isBusinessDay(result, weekendDays, excludedDates)) {
        addedDays++;
      }
    }
    
    // 处理小数部分（按9小时工作制）
    const fractionalDays = remainingDays - wholeDays;
    if (fractionalDays > 0) {
      const workingHoursToAdd = fractionalDays * 9; // 内部按9小时工作制
      let currentHour = result.getHours();
      let currentMinute = result.getMinutes();
      
      // 确保在工作时间内开始
      if (currentHour < 9) {
        currentHour = 9;
        currentMinute = 0;
      } else if (currentHour >= 18) {
        // 跳到下一个工作日的9:00
        result.setDate(result.getDate() + 1);
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        currentHour = 9;
        currentMinute = 0;
      }
      
      // 添加工作小时
      const totalMinutes = currentHour * 60 + currentMinute + workingHoursToAdd * 60;
      const finalHour = Math.floor(totalMinutes / 60);
      const finalMinute = totalMinutes % 60;
      
      // 如果超过18:00，需要跨到下一个工作日
      if (finalHour >= 18) {
        const overflowHours = finalHour - 18;
        const overflowMinutes = finalMinute;
        
        // 跳到下一个工作日
        result.setDate(result.getDate() + 1);
        while (!isBusinessDay(result, weekendDays, excludedDates)) {
          result.setDate(result.getDate() + 1);
        }
        
        result.setHours(9 + overflowHours, overflowMinutes, 0, 0);
      } else {
        result.setHours(finalHour, finalMinute, 0, 0);
      }
    }
    
    return result;
  };

  // 添加工作日 - 使用表格配置的休息日与节点自定义跳过日期
  const addBusinessDaysWithHolidays = (startDate: Date, businessDays: number, weekendDays: number[] = [], excludedDates: string[] = []): Date => {
    const result = new Date(startDate);
    let addedDays = 0;
    
    // 处理小数天数：先添加整数天，再处理小数部分
    const wholeDays = Math.floor(businessDays);
    const fractionalDays = businessDays - wholeDays;
    
    // 添加整数工作日
    while (addedDays < wholeDays) {
      result.setDate(result.getDate() + 1);
      if (isBusinessDay(result, weekendDays, excludedDates)) {
        addedDays++;
      }
    }
    
    // 处理小数部分（转换为小时，按24小时制）
    if (fractionalDays > 0) {
      const hoursToAdd = fractionalDays * 24; // 1天=24小时
      result.setHours(result.getHours() + hoursToAdd);
    }
    
    return result;
  };



  // 获取标签数据
  const fetchLabelOptions = async () => {
    setLabelLoading(true);
    try {
      // 获取标签表
      const labelTable = await bitable.base.getTable(LABEL_TABLE_ID);
      
      // 1. 先获取所有字段的元数据
      const fieldMetaList = await labelTable.getFieldMetaList();
      
      // 2. 筛选出标签1-标签10的字段
      const labelFields: {[key: string]: string} = {}; // 存储字段名到字段ID的映射
      
      for (const fieldMeta of fieldMetaList) {
        // 检查字段名是否匹配标签1-标签10的模式
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          labelFields[labelKey] = fieldMeta.id;
        }
      }
      
      console.log('找到的标签字段:', labelFields);
      
      // 3. 处理标签数据 - 从字段选项获取而不是从记录数据获取
      const options: {[key: string]: any[]} = {};
      
      // 初始化十个标签的选项数组
      for (let i = 1; i <= 10; i++) {
        options[`标签${i}`] = [];
      }
      
      // 4. 遍历标签字段，获取每个字段的选项
      for (const [labelKey, fieldId] of Object.entries(labelFields)) {
        try {
          const field = await labelTable.getField(fieldId);
          const fieldMeta = await field.getMeta();
          
          // 检查是否是选择字段（单选或多选）
          if (fieldMeta.type === FieldType.SingleSelect || fieldMeta.type === FieldType.MultiSelect) {
            const selectField = field as any; // 类型断言
            const fieldOptions = await selectField.getOptions();
            
            // 转换为我们需要的格式
            options[labelKey] = fieldOptions.map((option: any) => ({
              label: option.name,
              value: option.name
            }));
          }
        } catch (error) {
          console.warn(`获取${labelKey}字段选项失败:`, error);
          // 如果获取选项失败，保持空数组
          options[labelKey] = [];
        }
      }
      
      console.log('处理后的标签选项:', options);
      
      setLabelOptions(options);
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: `标签选项加载成功，共找到 ${Object.keys(labelFields).length} 个标签字段`
        });
      }
    } catch (error) {
      console.error('获取标签选项失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '获取标签选项失败，请检查表格配置'
        });
      }
    } finally {
      setLabelLoading(false);
    }
  };

  // 组件加载时获取标签数据和初始化起始时间
  useEffect(() => {
    const initializeData = async () => {
      await fetchLabelOptions();
      await initializeStartTime();
      await loadAvailableTables(); // 加载可用表列表
    };
    
    initializeData();
  }, []);

  // 初始化起始时间：从货期记录表获取，新记录则使用当前时间
  const initializeStartTime = async () => {
    try {
      const selection = await bitable.base.getSelection();
      const recordId = selection?.recordId || '';
      const tableId = selection?.tableId || '';
      
      if (recordId && tableId === DELIVERY_RECORD_TABLE_ID) {
        // 如果选中的是货期记录表的记录，从中获取起始时间
        const deliveryTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
        const deliveryRecord = await deliveryTable.getRecordById(recordId);
        const startTimeValue = deliveryRecord?.fields?.[DELIVERY_START_TIME_FIELD_ID];
        
        if (startTimeValue) {
          let extractedStartTime: Date | null = null;
          if (typeof startTimeValue === 'number') {
            extractedStartTime = new Date(startTimeValue);
          } else if (Array.isArray(startTimeValue) && startTimeValue.length > 0) {
            const timestamp = startTimeValue[0];
            if (typeof timestamp === 'number') {
              extractedStartTime = new Date(timestamp);
            }
          }
          
          if (extractedStartTime && !isNaN(extractedStartTime.getTime())) {
            setStartTime(extractedStartTime);
            return;
          }
        }
      }
      
      // 如果没有找到有效的起始时间，使用当前时间
      setStartTime(new Date());
    } catch (error) {
      console.error('初始化起始时间失败:', error);
      // 出错时使用当前时间作为默认值
      setStartTime(new Date());
    }
  };

  // 加载可用表列表
  const loadAvailableTables = async () => {
    try {
      setTablesLoading(true);
      const tableMetaList = await bitable.base.getTableMetaList();
      const tables = tableMetaList.map(table => ({
        id: table.id,
        name: table.name
      }));
      setAvailableTables(tables);
    } catch (error) {
      console.error('加载表列表失败:', error);
    } finally {
      setTablesLoading(false);
    }
  };

  // 加载指定表的视图列表
  const loadAvailableViews = async (tableId: string) => {
    if (!tableId) {
      setAvailableViews([]);
      return;
    }
    
    try {
      setViewsLoading(true);
      const table = await bitable.base.getTable(tableId);
      const viewMetaList = await table.getViewMetaList();
      const views = viewMetaList.map(view => ({
        id: view.id,
        name: view.name
      }));
      setAvailableViews(views);
    } catch (error) {
      console.error('加载视图列表失败:', error);
      setAvailableViews([]);
    } finally {
      setViewsLoading(false);
    }
  };

  // 处理表选择变化
  const handleBatchTableChange = (tableId: string) => {
    // 切换批量来源表时重置全局变量，避免旧状态残留
    resetGlobalState();
    setSelectedBatchTableId(tableId);
    setSelectedBatchViewId(''); // 重置视图选择
    loadAvailableViews(tableId); // 加载新表的视图列表
  };

  // 处理标签选择变化
  const handleLabelChange = (labelKey: string, value: string | string[]) => {
    setSelectedLabels(prev => ({
      ...prev,
      [labelKey]: value
    }));
  };

  // 清空标签选择
  const handleClearLabels = () => {
    setSelectedLabels({});
    setExpectedDate(null); // 清空客户期望日期
  };
  
  // 计算预计开始和完成时间
  const handleCalculateTimeline = async (
    skipValidation: boolean = false,
    overrideData?: {
      selectedRecords?: string[],
      recordDetails?: any[],
      selectedLabels?: {[key: string]: string | string[]},
      expectedDate?: Date | null,
      startTime?: Date | null
    },
    showUI: boolean = true // 新增参数控制是否显示UI
  ) => {
    // 使用传入的数据或全局状态
    const currentSelectedRecords = overrideData?.selectedRecords || selectedRecords;
    const currentRecordDetails = overrideData?.recordDetails || recordDetails;
    const currentSelectedLabels = overrideData?.selectedLabels || selectedLabels;
    const currentExpectedDate = overrideData?.expectedDate || expectedDate;
    const currentStartTime = overrideData?.startTime || startTime;
    
    console.log('=== handleCalculateTimeline - 使用的数据 ===');
    console.log('currentSelectedRecords:', currentSelectedRecords);
    console.log('currentSelectedLabels:', currentSelectedLabels);
    console.log('currentExpectedDate:', currentExpectedDate);
    console.log('currentStartTime:', currentStartTime);
    
    // 跳过验证（用于批量模式）
    if (!skipValidation) {
      // 检查是否选择了多条记录
      if (currentSelectedRecords.length > 1) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '计算时效功能仅支持单条记录，请重新选择单条记录后再试'
          });
        }
        return;
      }
      
      // 检查是否选择了记录
      if (currentSelectedRecords.length === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '请先选择一条记录'
          });
        }
        return;
      }
      
      // 检查是否选择了标签
      const hasSelectedLabels = Object.values(currentSelectedLabels).some(value => {
        return Array.isArray(value) ? value.length > 0 : Boolean(value);
      });
    
      if (!hasSelectedLabels) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '请先选择至少一个标签'
          });
        }
        return;
      }
    
      // 可选：检查是否选择了客户期望日期
      if (!currentExpectedDate) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'info',
            message: '建议选择客户期望日期以便更好地进行时效计算'
          });
        }
      }
    }
  
    // 移除冗余日志：客户期望日期输出
    setTimelineLoading(true);
    // 生成模式：输出当前数据结构，便于与批量模式对比
    try {
      console.group('=== 生成模式：计算时效 - 当前数据结构 ===');
      // 模式与核心输入
      console.log('mode:', mode);
      console.log('selectedRecords:', currentSelectedRecords);
      console.log('recordDetails:', currentRecordDetails);
      console.log('selectedLabels:', currentSelectedLabels);
      console.log('expectedDate:', currentExpectedDate);
      console.groupEnd();
    } catch (logErr) {
      console.warn('生成模式结构化日志输出失败:', logErr);
    }
    try {
      // 构建业务选择的所有标签值集合（用于快速查找）
      const businessLabelValues = new Set<string>();
      for (const [labelKey, selectedValue] of Object.entries(currentSelectedLabels)) {
        if (selectedValue) {
          const values = Array.isArray(selectedValue) ? selectedValue : [selectedValue];
          values.forEach(value => {
            if (typeof value === 'string' && value.trim()) {
              businessLabelValues.add(value.trim());
            }
          });
        }
      }
      
      // 已移除冗余日志：业务选择标签值
      const timelineTable = await bitable.base.getTable(TIMELINE_TABLE_ID);
      const timelineFieldMetaList = await timelineTable.getFieldMetaList();
      const timelineLabelFields: {[key: string]: string} = {};
      
      // 构建时效表的标签字段映射（只执行一次）
      let relationshipFieldId = ''; // 关系字段ID
      let calculationMethodFieldId = ''; // 时效计算方式字段ID
      
      for (const fieldMeta of timelineFieldMetaList) {
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          timelineLabelFields[labelKey] = fieldMeta.id;
        }
        // 查找关系字段
        if (fieldMeta.name === '关系' || fieldMeta.id === 'fldaIDAhab') {
          relationshipFieldId = fieldMeta.id;
        }
        // 查找时效计算方式字段
        if (fieldMeta.name === '时效计算方式' || fieldMeta.id === 'fldxfLZNUu') {
          calculationMethodFieldId = fieldMeta.id;
        }
      }
      
      console.log('时效表标签字段映射:', timelineLabelFields);
      console.log('关系字段ID:', relationshipFieldId);
      
      // 1. 先获取匹配的流程节点（复用预览功能的逻辑）
      const processTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      const processRecordsResult = await processTable.getRecords({
        pageSize: 5000
      });
      
      const processRecords = processRecordsResult.records || [];
      const matchedProcessNodes: any[] = [];
      
      // 匹配流程配置节点
      for (const record of processRecords) {
        const fields = record.fields;
        const processLabels = fields[PROCESS_LABEL_FIELD_ID];
        const nodeName = fields[NODE_NAME_FIELD_ID];
        const processOrder = fields[PROCESS_ORDER_FIELD_ID]; // 获取流程顺序
        
        if (!processLabels || !nodeName) continue;
        
        // 处理流程配置表中的标签数据 - 修复多选字段处理
        let processLabelTexts: string[] = [];
        if (typeof processLabels === 'string') {
          processLabelTexts = [processLabels];
        } else if (processLabels && processLabels.text) {
          processLabelTexts = [processLabels.text];
        } else if (Array.isArray(processLabels) && processLabels.length > 0) {
          // 处理多选字段，获取所有选项的值
          processLabelTexts = processLabels.map(item => {
            if (typeof item === 'string') {
              return item;
            } else if (item && item.text) {
              return item.text;
            } else if (item && item.value) {
              return item.value;
            }
            return String(item);
          }).filter(text => text && text.trim());
        }
        
        // 处理节点名称
        let nodeNameText = '';
        if (typeof nodeName === 'string') {
          nodeNameText = nodeName;
        } else if (nodeName.text) {
          nodeNameText = nodeName.text;
        }
        
        // 处理流程顺序
        let orderValue = 0;
        if (typeof processOrder === 'number') {
          orderValue = processOrder;
        } else if (typeof processOrder === 'string') {
          orderValue = parseInt(processOrder) || 0;
        } else if (processOrder && processOrder.value !== undefined) {
          orderValue = processOrder.value;
        }
        
        if (processLabelTexts.length === 0 || !nodeNameText) continue;
        
        // 检查是否匹配当前选择的标签 - 修复匹配逻辑
        let isMatched = false;
        const matchedLabels: string[] = [];
        
        for (const [labelKey, labelValue] of Object.entries(currentSelectedLabels)) {
          if (!labelValue) continue;
          
          const valuesToCheck = Array.isArray(labelValue) ? labelValue : [labelValue];
          
          for (const value of valuesToCheck) {
            // 检查用户选择的值是否在流程配置的任何一个标签选项中
            const isValueMatched = processLabelTexts.some(processLabelText => {
              // 直接匹配
              if (processLabelText === value) {
                return true;
              }
              // 包含匹配（用于处理可能的格式差异）
              if (processLabelText.includes(value)) {
                return true;
              }
              return false;
            });
            
            if (isValueMatched) {
              isMatched = true;
              matchedLabels.push(`${labelKey}: ${value}`);
              console.log(`匹配成功: ${labelKey} = ${value}`);
            } else {
              console.log(`匹配失败: ${labelKey} = ${value}, 流程配置标签: [${processLabelTexts.join(', ')}]`);
            }
          }
        }
        
        // 处理休息日配置 - 完全从表格字段获取
        let weekendDays: number[] = [];
        const weekendDaysField = fields[WEEKEND_DAYS_FIELD_ID]; // 获取休息日配置
        if (weekendDaysField) {
          console.log('原始休息日字段数据:', weekendDaysField);
          
          if (Array.isArray(weekendDaysField)) {
            // 多选字段返回数组，每个元素可能是选项对象
            weekendDays = weekendDaysField.map(item => {
              // 处理选项对象 {id: "xxx", text: "0"} 或直接的值
              if (item && typeof item === 'object') {
                // 如果是选项对象，取text或id字段
                const value = item.text || item.id || item.value;
                if (typeof value === 'string') {
                  const parsed = parseInt(value);
                  return !isNaN(parsed) && parsed >= 0 && parsed <= 6 ? parsed : null;
                } else if (typeof value === 'number') {
                  return value >= 0 && value <= 6 ? value : null;
                }
              } else if (typeof item === 'string') {
                const parsed = parseInt(item);
                return !isNaN(parsed) && parsed >= 0 && parsed <= 6 ? parsed : null;
              } else if (typeof item === 'number') {
                return item >= 0 && item <= 6 ? item : null;
              }
              return null;
            }).filter(day => day !== null) as number[];
          } else if (typeof weekendDaysField === 'string') {
            // 如果是字符串，尝试解析
            try {
              const parsed = JSON.parse(weekendDaysField);
              if (Array.isArray(parsed)) {
                weekendDays = parsed.filter(day => typeof day === 'number' && day >= 0 && day <= 6);
              }
            } catch {
              // 如果解析失败，尝试按逗号分割
              const parts = weekendDaysField.split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n) && n >= 0 && n <= 6);
              if (parts.length > 0) {
                weekendDays = parts;
              }
            }
          } else if (typeof weekendDaysField === 'number' && weekendDaysField >= 0 && weekendDaysField <= 6) {
            weekendDays = [weekendDaysField];
          }
          
          console.log('解析后的休息日配置:', weekendDays);
        }
        // 如果表格中没有配置休息日或配置为空，则该节点没有固定休息日
        // 这样就完全依赖表格数据，不会有任何硬编码的默认值
        
        // 处理不参与计算日期（自定义跳过日期）
        let excludedDates: string[] = [];
        const excludedDatesField = fields[EXCLUDED_DATES_FIELD_ID];
        if (excludedDatesField) {
          console.log('原始不参与计算日期字段数据:', excludedDatesField);
          if (Array.isArray(excludedDatesField)) {
            excludedDates = excludedDatesField.map(item => {
              if (item && typeof item === 'object') {
                const val = item.text || item.name || item.value || item.id || '';
                return String(val).trim();
              }
              return String(item).trim();
            }).filter(d => !!d);
          } else if (typeof excludedDatesField === 'string') {
            excludedDates = excludedDatesField.split(/[\,\s]+/).map(s => s.trim()).filter(Boolean);
          } else if (excludedDatesField && typeof excludedDatesField === 'object' && excludedDatesField.text) {
            excludedDates = [String(excludedDatesField.text).trim()].filter(Boolean);
          }
          console.log('解析后的不参与计算日期:', excludedDates);
        }
        
        if (isMatched) {
          // 获取起始日期调整规则
          const startDateRule = fields[START_DATE_RULE_FIELD_ID];
          // 获取JSON格式的日期调整规则
          const dateAdjustmentRule = fields[DATE_ADJUSTMENT_RULE_FIELD_ID];
          
          matchedProcessNodes.push({
            id: record.id,
            nodeName: nodeNameText,
            processLabels: processLabelTexts.join(', '),
            matchedLabels: matchedLabels,
            processOrder: orderValue, // 添加流程顺序
            weekendDays: weekendDays, // 添加休息日配置
            excludedDates: excludedDates, // 添加自定义跳过日期
            startDateRule: startDateRule, // 添加起始日期调整规则
            dateAdjustmentRule: dateAdjustmentRule // 添加JSON格式日期调整规则
          });
        }
      }
      
      // 按流程顺序排序
      matchedProcessNodes.sort((a, b) => a.processOrder - b.processOrder);
      
      console.log('按顺序排列的流程节点:', matchedProcessNodes);
      
      // 2. 优化：预先获取所有时效数据并建立索引
      const timelineRecordsResult = await timelineTable.getRecords({
        pageSize: 5000
      });
      
      const timelineRecords = timelineRecordsResult.records || [];
      
      // 优化2：预处理时效数据，建立节点名称到记录的映射
      const timelineIndexByNode = new Map<string, any[]>();
      
      for (const timelineRecord of timelineRecords) {
        const timelineFields = timelineRecord.fields;
        const timelineNodeName = timelineFields[TIMELINE_NODE_FIELD_ID];
        
        // 处理时效表中的节点名称
        let timelineNodeNames: string[] = [];
        
        if (typeof timelineNodeName === 'string') {
          timelineNodeNames = timelineNodeName.split(',').map(name => name.trim());
        } else if (Array.isArray(timelineNodeName)) {
          timelineNodeNames = timelineNodeName.map(item => {
            if (typeof item === 'string') {
              return item.trim();
            } else if (item && item.text) {
              return item.text.trim();
            }
            return '';
          }).filter(name => name);
        } else if (timelineNodeName && timelineNodeName.text) {
          timelineNodeNames = timelineNodeName.text.split(',').map(name => name.trim());
        }
        
        // 为每个节点名称建立索引
        for (const nodeName of timelineNodeNames) {
          const normalizedName = nodeName.toLowerCase();
          if (!timelineIndexByNode.has(normalizedName)) {
            timelineIndexByNode.set(normalizedName, []);
          }
          timelineIndexByNode.get(normalizedName)!.push({
            record: timelineRecord,
            fields: timelineFields
          });
        }
      }
      
      console.log('时效数据索引构建完成，节点数量:', timelineIndexByNode.size);
      
      const results: any[] = [];
      
      // 3. 按顺序为每个匹配的流程节点查找时效数据并计算累积时间
      let cumulativeStartTime = currentStartTime ? new Date(currentStartTime) : new Date(); // 累积开始时间
      
      for (let i = 0; i < matchedProcessNodes.length; i++) {
        const processNode = matchedProcessNodes[i];
        let timelineValue = null;
        let matchedTimelineRecord = null;
        
        // 优化3：使用索引快速查找候选记录
        const normalizedProcessName = processNode.nodeName.trim().toLowerCase();
        const candidateRecords = timelineIndexByNode.get(normalizedProcessName) || [];
        
        console.log(`节点 ${processNode.nodeName} 找到 ${candidateRecords.length} 个候选时效记录`);
        
        // 在候选记录中进行标签匹配
        let matchedCandidates = []; // 收集所有匹配的候选记录
        
        for (const candidate of candidateRecords) {
          const { record: timelineRecord, fields: timelineFields } = candidate;
          
          // 优化4：使用预构建的字段映射进行标签匹配
          let isLabelsMatched = true;
          
          // 检查时效表中每个有值的标签是否都包含在业务标签中
          for (const [labelKey, timelineFieldId] of Object.entries(timelineLabelFields)) {
            const timelineLabelValue = timelineFields[timelineFieldId];
            
            // 处理时效表中的标签值
            let timelineLabelTexts: string[] = [];
            
            if (typeof timelineLabelValue === 'string' && timelineLabelValue.trim()) {
              timelineLabelTexts = [timelineLabelValue.trim()];
            } else if (timelineLabelValue && timelineLabelValue.text && timelineLabelValue.text.trim()) {
              timelineLabelTexts = [timelineLabelValue.text.trim()];
            } else if (Array.isArray(timelineLabelValue) && timelineLabelValue.length > 0) {
              // 多选字段，获取所有值
              timelineLabelTexts = timelineLabelValue.map(item => {
                if (typeof item === 'string') return item.trim();
                if (item && item.text) return item.text.trim();
                return '';
              }).filter(text => text);
            }
            
            // 如果时效表中该标签有值，则检查该标签的所有值是否都包含在业务标签中
            if (timelineLabelTexts.length > 0) {
              let allValuesMatched = true;
              
              // 优化5：使用Set的has方法进行快速查找
              for (const timelineText of timelineLabelTexts) {
                if (!businessLabelValues.has(timelineText)) {
                  allValuesMatched = false;
                  console.log(`时效表标签 ${labelKey} 的值 "${timelineText}" 不在业务选择的标签中`);
                  break;
                }
              }
              
              if (!allValuesMatched) {
                console.log(`时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 不完全包含在业务选择的标签中`);
                isLabelsMatched = false;
                break;
              } else {
                console.log(`时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 完全匹配成功`);
              }
            }
            // 如果时效表中该标签为空，则跳过检查（空标签不影响匹配）
          }
          
          // 只有标签匹配成功才获取时效数据
                if (isLabelsMatched) {
                  // 找到匹配的节点，获取时效值
                  const timelineValueField = timelineFields[TIMELINE_FIELD_ID];
                  // 获取关系字段值
                  const relationshipField = timelineFields[relationshipFieldId];
                  // 获取时效计算方式字段值
                  const calculationMethodField = timelineFields[calculationMethodFieldId];
                  
                  if (timelineValueField !== null && timelineValueField !== undefined) {
                    let candidateTimelineValue = 0;
                    
                    // 解析时效值
                    if (typeof timelineValueField === 'number') {
                      candidateTimelineValue = timelineValueField;
                    } else if (typeof timelineValueField === 'string') {
                      const parsedValue = parseFloat(timelineValueField);
                      candidateTimelineValue = isNaN(parsedValue) ? 0 : parsedValue;
                    } else if (timelineValueField && typeof timelineValueField === 'object' && timelineValueField.value !== undefined) {
                      candidateTimelineValue = timelineValueField.value;
                    }
                    
                    // 获取计算方式
                    let calculationMethod = '外部'; // 默认值
                    if (calculationMethodField) {
                      if (typeof calculationMethodField === 'string') {
                        calculationMethod = calculationMethodField;
                      } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
                        calculationMethod = calculationMethodField.text;
                      }
                    }
                    
                    // 根据计算方式转换时效值（小时转天）
                    let convertedTimelineValue = 0;
                    if (calculationMethod === '内部') {
                      convertedTimelineValue = Math.round((candidateTimelineValue / 9) * 1000) / 1000; // 精确到3位小数
                      console.log(`内部计算方式: ${candidateTimelineValue}小时 → ${convertedTimelineValue.toFixed(3)}天`);
                    } else {
                      convertedTimelineValue = Math.round((candidateTimelineValue / 24) * 1000) / 1000; // 精确到3位小数
                      console.log(`外部计算方式: ${candidateTimelineValue}小时 → ${convertedTimelineValue.toFixed(3)}天`);
                    }
                    
                    // 获取关系类型
                    let relationshipType = '默认';
                    if (relationshipField) {
                      if (typeof relationshipField === 'string') {
                        relationshipType = relationshipField;
                      } else if (relationshipField && typeof relationshipField === 'object' && relationshipField.text) {
                        relationshipType = relationshipField.text;
                      }
                    }
                    
                    // 调试时效记录对象结构
                    console.log('时效记录对象结构:', timelineRecord);
                    console.log('记录ID字段:', {
                      id: timelineRecord.id,
                      recordId: timelineRecord.recordId,
                      _id: timelineRecord._id,
                      record_id: timelineRecord.record_id
                    });
                    
                    matchedCandidates.push({
                      record: timelineRecord,
                      timelineValue: convertedTimelineValue, // 使用转换后的值
                      relationshipType: relationshipType,
                      calculationMethod: calculationMethod, // 记录计算方式
                      originalHours: candidateTimelineValue // 保留原始小时值用于日志
                    });
                    
                    // 移除单条记录的详细日志输出，避免日志冗余
                    // console.log(`节点 ${processNode.nodeName} 找到匹配记录:`, {
                    //   记录ID: timelineRecord.id || timelineRecord.recordId || timelineRecord._id || timelineRecord.record_id,
                    //   原始时效值小时: candidateTimelineValue,
                    //   转换后天数: convertedTimelineValue,
                    //   关系类型: relationshipType,
                    //   时效计算方式: calculationMethod
                    // });
                  }
                }
        }
        
        // 在 matchedCandidates 处理之前定义 processingRule
        let processingRule = '默认'; // 默认值
        
        // 根据关系字段和时效计算方式决定如何处理多个匹配的记录
        if (matchedCandidates.length > 0) {
          // 检查所有匹配记录的关系类型和计算方式
          const relationshipTypes = [...new Set(matchedCandidates.map(c => c.relationshipType))];
          const calculationMethods = [...new Set(matchedCandidates.map(c => c.calculationMethod))];
          
          if (relationshipTypes.length > 1) {
            console.warn(`节点 ${processNode.nodeName} 存在多种关系类型:`, relationshipTypes);
          }
          if (calculationMethods.length > 1) {
            console.warn(`节点 ${processNode.nodeName} 存在多种时效计算方式:`, calculationMethods);
          }
          
          // 使用第一个匹配记录的关系类型和计算方式作为处理方式
          const primaryRelationshipType = matchedCandidates[0].relationshipType;
          const primaryCalculationMethod = matchedCandidates[0].calculationMethod;
          
          // 添加调试日志
          console.log(`节点 ${processNode.nodeName} 调试信息:`);
          console.log('primaryCalculationMethod:', primaryCalculationMethod);
          console.log('primaryRelationshipType:', primaryRelationshipType);
          console.log('所有关系类型:', relationshipTypes);
          console.log('所有计算方式:', calculationMethods);
          
          let finalTimelineValue = 0;
          
          // 使用关系字段决定处理方式（累加值、最大值、默认）
          processingRule = primaryRelationshipType || '默认';
          
          console.log('processingRule:', processingRule);
          
          if (processingRule === '累加值') {
            finalTimelineValue = matchedCandidates.reduce((sum, candidate) => sum + candidate.timelineValue, 0);
            const totalOriginalHours = matchedCandidates.reduce((sum, candidate) => sum + candidate.originalHours, 0);
            
            console.log(`节点 ${processNode.nodeName} 累加值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`累加结果: 总计${totalOriginalHours}小时 → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          } else if (processingRule === '最大值') {
            finalTimelineValue = Math.max(...matchedCandidates.map(c => c.timelineValue));
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            
            console.log(`节点 ${processNode.nodeName} 最大值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`最大值结果: ${maxCandidate?.originalHours}小时(${maxCandidate?.calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = maxCandidate?.record || matchedCandidates[0].record;
          } else {
            finalTimelineValue = matchedCandidates[0].timelineValue;
            
            console.log(`节点 ${processNode.nodeName} 默认处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`默认结果: 使用第一条记录 ${matchedCandidates[0].originalHours}小时(${matchedCandidates[0].calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          }
          
          timelineValue = finalTimelineValue;
          // matchedTimelineRecord 已在上面的处理逻辑中设置
        }
        

        
        // 计算当前节点的开始和完成时间（使用工作日计算）
        const calculateTimeline = (startDate: Date, timelineValue: number, calculationMethod: string = '外部') => {
          // 根据计算方式调整开始时间
          const adjustedStartDate = adjustToNextWorkingHour(startDate, calculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          
          let endDate: Date;
          if (calculationMethod === '内部') {
            // 使用内部工作时间计算
            endDate = addInternalBusinessTime(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            // 使用原有的24小时制计算
            endDate = addBusinessDaysWithHolidays(adjustedStartDate, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
          
          return {
          startDate: formatDate(adjustedStartDate, 'STORAGE_FORMAT'),
          endDate: formatDate(endDate, 'STORAGE_FORMAT')
        };
        };
        
        let nodeStartTime = new Date(cumulativeStartTime);
        
        // 应用起始日期调整规则
        if (processNode.startDateRule) {
          let ruleJson = '';
          if (typeof processNode.startDateRule === 'string') {
            ruleJson = processNode.startDateRule;
          } else if (processNode.startDateRule && processNode.startDateRule.text) {
            ruleJson = processNode.startDateRule.text;
          }
          
          if (ruleJson.trim()) {
            nodeStartTime = adjustStartDateByRule(nodeStartTime, ruleJson);
            console.log(`节点 ${processNode.nodeName} 应用起始日期调整规则后的开始时间:`, formatDate(nodeStartTime));
          }
        }
        
        // 应用JSON格式日期调整规则
        let ruleDescription = '';
        if (processNode.dateAdjustmentRule) {
          console.log('原始dateAdjustmentRule:', processNode.dateAdjustmentRule);
          let ruleText = '';
          if (typeof processNode.dateAdjustmentRule === 'string') {
            ruleText = processNode.dateAdjustmentRule;
          } else if (Array.isArray(processNode.dateAdjustmentRule)) {
            // 处理富文本数组格式
            ruleText = processNode.dateAdjustmentRule
              .filter(item => item.type === 'text')
              .map(item => item.text)
              .join('');
          } else if (processNode.dateAdjustmentRule && processNode.dateAdjustmentRule.text) {
            ruleText = processNode.dateAdjustmentRule.text;
          }
          
          console.log('解析后的ruleText:', ruleText);
          console.log('调整前的nodeStartTime:', formatDate(nodeStartTime));
          
          if (ruleText && ruleText.trim() !== '') {
            const result = adjustStartDateByJsonRule(nodeStartTime, ruleText);
            nodeStartTime = result.adjustedDate;
            ruleDescription = result.description || '';
            console.log(`节点 ${processNode.nodeName} 应用JSON日期调整规则后的开始时间:`, formatDate(nodeStartTime));
          }
        }
        
        // 获取当前节点的计算方式
        let nodeCalculationMethod = '外部'; // 默认值
        if (matchedCandidates.length > 0) {
          nodeCalculationMethod = matchedCandidates[0].calculationMethod;
        } else if (matchedTimelineRecord) {
          const calculationMethodField = matchedTimelineRecord.fields[calculationMethodFieldId];
          if (calculationMethodField) {
            if (typeof calculationMethodField === 'string') {
              nodeCalculationMethod = calculationMethodField;
            } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
              nodeCalculationMethod = calculationMethodField.text;
            }
          }
        }
        
        const timelineResult = timelineValue ? 
          calculateTimeline(nodeStartTime, timelineValue, nodeCalculationMethod) : 
          {
            startDate: formatDate(nodeStartTime, 'STORAGE_FORMAT'),
            endDate: '未找到时效数据'
          };
        
        let nodeEndTime: Date;
        if (timelineValue) {
          const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          if (nodeCalculationMethod === '内部') {
            nodeEndTime = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
        } else {
          nodeEndTime = new Date(nodeStartTime);
        }
        
        // 计算跳过的天数
        const skippedWeekends = calculateSkippedWeekends(nodeStartTime, nodeEndTime, processNode.weekendDays);
        const actualDays = calculateActualDays(timelineResult.startDate, timelineResult.endDate);
        
        // 计算时间范围内实际跳过的自定义日期
        const excludedDatesInRange = calculateExcludedDatesInRange(nodeStartTime, nodeEndTime, processNode.excludedDates || []);
        
        results.push({
          processOrder: processNode.processOrder,
          nodeName: processNode.nodeName,
          matchedLabels: processNode.matchedLabels,
          timelineValue: timelineValue,
          estimatedStart: timelineResult.startDate,
          estimatedEnd: timelineResult.endDate,
          timelineRecordId: matchedTimelineRecord ? 
            (matchedTimelineRecord.id || matchedTimelineRecord.recordId || matchedTimelineRecord._id || matchedTimelineRecord.record_id) : null,
          // 新增：保存所有匹配记录的信息（用于累加情况）
          allMatchedRecords: matchedCandidates.length > 1 ? matchedCandidates.map(candidate => ({
            recordId: candidate.record.id || candidate.record.recordId || candidate.record._id || candidate.record.record_id,
            timelineValue: candidate.timelineValue,
            originalHours: candidate.originalHours,
            calculationMethod: candidate.calculationMethod,
            relationshipType: candidate.relationshipType
          })) : null,
          // 新增：标识是否为累加处理
          isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1,
          weekendDaysConfig: processNode.weekendDays, // 新增：保存休息日配置用于显示
          excludedDates: processNode.excludedDates || [], // 新增：保存不参与计算日期用于显示与快照
          // 新增：保存时间范围内实际跳过的日期
          actualExcludedDates: excludedDatesInRange.dates,
          actualExcludedDatesCount: excludedDatesInRange.count,
          calculationMethod: nodeCalculationMethod, // 新增：保存计算方式
          ruleDescription: ruleDescription, // 新增：保存规则描述
          skippedWeekends: skippedWeekends,
          actualDays: actualDays,
          // 新增：保存调整规则用于重新计算
          startDateRule: processNode.startDateRule,
          dateAdjustmentRule: processNode.dateAdjustmentRule,
          adjustmentDescription: ruleDescription // 新增：保存调整规则描述
        });
        
        // 更新累积时间：当前节点的完成时间成为下一个节点的开始时间
        if (timelineValue) {
          cumulativeStartTime = new Date(nodeEndTime);
        }
        
        console.log(`节点 ${processNode.nodeName} (顺序: ${processNode.processOrder}):`, {
          开始时间: formatDate(nodeStartTime),
          完成时间: formatDate(nodeEndTime),
          时效天数: timelineValue,
          计算方式: nodeCalculationMethod
        });
      }
      
      setTimelineResults(results);
      if (showUI) {
        setTimelineVisible(true);
      }
      
      console.log('按流程顺序计算的时效结果:', results);
      
      return results; // 返回计算结果
      
    } catch (error) {
      console.error('计算时效失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '计算时效失败，请检查表格配置'
        });
      }
      throw error; // 重新抛出错误
    } finally {
      setTimelineLoading(false);
    }
  };
  
  // 复合调整处理函数：根据缓冲期和交期余量状态决定调整方式
  const handleComplexAdjustment = (nodeIndex: number, adjustment: number) => {
    // 计算当前状态
    const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
    const baseBuferDays = baseBufferDays;
    
    // 智能缓冲期计算逻辑
    let dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
    
    // 只有在缓冲期为0时才检查最终限制：最后节点预计完成时间是否已达到客户期望日期
    let hasReachedFinalLimit = false;
    if (dynamicBufferDays === 0 && expectedDate && timelineResults.length > 0) {
      // 获取有效的最后流程完成日期
      let effectiveLastProcess = null;
      let lastCompletionDate = null;
      
      for (let i = timelineResults.length - 1; i >= 0; i--) {
        const process = timelineResults[i];
        const processDate = new Date(process.estimatedEnd);
        
        if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
          effectiveLastProcess = process;
          lastCompletionDate = processDate;
          break;
        }
      }
      
      if (!effectiveLastProcess) {
        effectiveLastProcess = timelineResults[timelineResults.length - 1];
        lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
      }
      
      // 计算最后流程完成日期（包含调整）
      const adjustedCompletionDate = new Date(lastCompletionDate);
      adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
      
      // 检查是否已达到客户期望日期
      const timeDiffToExpected = expectedDate.getTime() - adjustedCompletionDate.getTime();
      const daysToExpected = Math.ceil(timeDiffToExpected / (1000 * 60 * 60 * 24));
      hasReachedFinalLimit = daysToExpected <= 0;
    }
    
    // 如果已达到最终限制且是正向调整，则禁止操作
    if (hasReachedFinalLimit && adjustment > 0) {
      return;
    }
    
    // 调整逻辑：
    // 1. 优先使用缓冲期
    // 2. 缓冲期为0时，通过调整节点时效值实现连锁传递
    if (adjustment > 0) {
      // 正数调整：需要扣减
      if (dynamicBufferDays > 0) {
        // 1. 缓冲期 > 0，优先扣减缓冲期（通过调整节点时间）
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      } else {
        // 2. 缓冲期 = 0，通过调整节点时效值实现连锁传递
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      }
    } else if (adjustment < 0) {
      // 负数调整：需要恢复
      if (completionDateAdjustment > 0) {
        // 1. 优先恢复最后流程完成日期的调整
        const restoreAmount = Math.min(-adjustment, completionDateAdjustment);
        setCompletionDateAdjustment(completionDateAdjustment - restoreAmount);
        const remainingRestore = -adjustment - restoreAmount;
        
        if (remainingRestore > 0) {
          // 2. 如果还有剩余恢复量，恢复缓冲期（通过调整节点时间）
          const updatedResults = handleTimelineAdjustment(nodeIndex, -remainingRestore);
          // 如果调整失败，不进行后续操作
          if (!updatedResults) return;
        }
      } else if (totalAdjustments > 0) {
        // 直接恢复缓冲期
        const updatedResults = handleTimelineAdjustment(nodeIndex, adjustment);
        // 如果调整失败，不进行后续操作
        if (!updatedResults) return;
      }
    }
  };
  
  // 调整时效值的函数
  const handleTimelineAdjustment = (nodeIndex: number, adjustment: number) => {
    const newAdjustments = { ...timelineAdjustments };
    const currentAdjustment = newAdjustments[nodeIndex] || 0;
    const newAdjustment = currentAdjustment + adjustment;
    
    // 防止调整后的时效值小于0（优先使用原始时效值，其次使用上次重算后的值）
    const baseValue = (typeof timelineResults[nodeIndex]?.timelineValue === 'number')
      ? timelineResults[nodeIndex]!.timelineValue
      : (typeof timelineResults[nodeIndex]?.adjustedTimelineValue === 'number')
        ? timelineResults[nodeIndex]!.adjustedTimelineValue
        : 0;
    if (baseValue + newAdjustment < 0) {
      return null;
    }
    
    // 检查当前调整的节点是否为周转周期节点
    const currentNodeName = timelineResults[nodeIndex]?.nodeName;
    const isTurnoverNode = currentNodeName === '周转周期';
    
    // 如果调整的是周转周期节点，直接返回（禁用手动调整）
    if (isTurnoverNode) {
      return null;
    }
    
    newAdjustments[nodeIndex] = newAdjustment;
    
    // 查找周转周期节点的索引
    const turnoverNodeIndex = timelineResults.findIndex(result => result.nodeName === '周转周期');
    
    // 如果存在周转周期节点，进行反向调整
    if (turnoverNodeIndex !== -1 && turnoverNodeIndex !== nodeIndex) {
      const turnoverCurrentAdjustment = newAdjustments[turnoverNodeIndex] || 0;
      const turnoverBaseValue = (typeof timelineResults[turnoverNodeIndex]?.timelineValue === 'number')
        ? timelineResults[turnoverNodeIndex]!.timelineValue
        : (typeof timelineResults[turnoverNodeIndex]?.adjustedTimelineValue === 'number')
          ? timelineResults[turnoverNodeIndex]!.adjustedTimelineValue
          : 0;
      
      // 计算周转周期的反向调整值
      const turnoverNewAdjustment = turnoverCurrentAdjustment - adjustment;
      
      // 确保周转周期调整后的值不小于0
      if (turnoverBaseValue + turnoverNewAdjustment >= 0) {
        newAdjustments[turnoverNodeIndex] = turnoverNewAdjustment;
      }
    }
    
    setTimelineAdjustments(newAdjustments);
    
    // 使用智能重算逻辑，只重算被调整的节点及其后续节点
    recalculateTimeline(newAdjustments);
    return timelineResults;
  };

  // 获取重新计算后的时间线结果（不更新状态）
  const getRecalculatedTimeline = (adjustments: {[key: number]: number}) => {
    const updatedResults = [...timelineResults];
    let cumulativeStartTime = startTime ? new Date(startTime) : new Date(); // 从起始时间开始
    
    for (let i = 0; i < updatedResults.length; i++) {
      const result = updatedResults[i];
      const baseTimelineValue = (typeof result.timelineValue === 'number')
        ? result.timelineValue
        : (typeof result.adjustedTimelineValue === 'number')
          ? result.adjustedTimelineValue
          : 0;
      const adjustment = adjustments[i] || 0;
      const adjustedTimelineValue = baseTimelineValue + adjustment;
      
      // 计算当前节点的开始时间
      let nodeStartTime = new Date(cumulativeStartTime);
      
      // 获取节点的计算方式、周末天数和排除日期
      const nodeCalculationMethod = result.calculationMethod || 'external';
      const nodeWeekendDays = result.weekendDays || [];
      const nodeExcludedDates = result.excludedDates || [];
      
      // 获取调整规则描述
      const ruleDescription = result.ruleDescription || '';
      
      // 计算节点的结束时间
      let nodeEndTime;
      if (adjustedTimelineValue > 0) {
        const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
        if (nodeCalculationMethod === 'internal') {
          nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        } else {
          nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        }
      } else {
        nodeEndTime = new Date(nodeStartTime);
      }
      
      // 计算跳过的天数
      const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates) : nodeStartTime;
      const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays);
      const estimatedStartStr = formatDate(adjustedStartTime);
      const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
      const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
      
      // 计算时间范围内实际跳过的自定义日期
      const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
      
      // 更新结果
      updatedResults[i] = {
        ...result,
        adjustedTimelineValue: adjustedTimelineValue,
        estimatedStart: estimatedStartStr,
        estimatedEnd: estimatedEndStr,
        adjustment: adjustment,
        calculationMethod: nodeCalculationMethod, // 保持计算方式
        skippedWeekends: skippedWeekends,
        actualDays: actualDays,
        // 更新时间范围内实际跳过的日期
        actualExcludedDates: excludedDatesInRange.dates,
        actualExcludedDatesCount: excludedDatesInRange.count,
        adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
        ruleDescription: ruleDescription // 添加更新后的规则描述
      };
      
      // 更新累积时间：当前节点的完成时间成为下一个节点的开始时间
      if (adjustedTimelineValue > 0) {
        cumulativeStartTime = new Date(nodeEndTime);
      }
    }
    
    return updatedResults;
  };

  // 重新计算时间线的函数
  const recalculateTimeline = (adjustments: {[key: number]: number}, forceRecalculateAll: boolean = false) => {
    const updatedResults = [...timelineResults];
    
    // 找到第一个被调整的节点索引
    const adjustedIndices = Object.keys(adjustments).map(k => parseInt(k)).filter(i => adjustments[i] !== 0);
    
    // 找到有实际完成时间的节点
    const actualCompletionIndices = Object.keys(actualCompletionDates)
      .map(k => parseInt(k))
      .filter(i => actualCompletionDates[i] !== null && actualCompletionDates[i] !== undefined);
    
    // 如果没有调整且不是强制重算，但有实际完成时间，需要重新计算
    if (adjustedIndices.length === 0 && !forceRecalculateAll && actualCompletionIndices.length === 0) {
      return; // 没有调整也没有实际完成时间，直接返回
    }
    
    // 确定第一个需要重新计算的节点索引
    let firstAdjustedIndex: number;
    
    if (forceRecalculateAll) {
      firstAdjustedIndex = 0;
    } else if (actualCompletionIndices.length > 0) {
      // 如果有实际完成时间，从最早有实际完成时间的节点的下一个节点开始重新计算
      const earliestActualCompletionIndex = Math.min(...actualCompletionIndices);
      const earliestAdjustmentIndex = adjustedIndices.length > 0 ? Math.min(...adjustedIndices) : Infinity;
      firstAdjustedIndex = Math.min(earliestActualCompletionIndex + 1, earliestAdjustmentIndex);
      console.log(`检测到实际完成时间，从节点 ${firstAdjustedIndex} 开始重新计算`);
    } else {
      firstAdjustedIndex = adjustedIndices.length > 0 ? Math.min(...adjustedIndices) : 0;
    }
    
    // 确保索引不超出范围
    firstAdjustedIndex = Math.max(0, Math.min(firstAdjustedIndex, updatedResults.length - 1));
    
    // 确定累积开始时间
    let cumulativeStartTime: Date;
    if (firstAdjustedIndex === 0) {
      // 如果调整的是第一个节点，从起始时间开始
      cumulativeStartTime = startTime ? new Date(startTime) : new Date();
    } else {
      // 如果调整的不是第一个节点，从前一个节点的结束时间开始
      const previousResult = updatedResults[firstAdjustedIndex - 1];
      const previousIndex = firstAdjustedIndex - 1;
      
      // 检查前一个节点是否有实际完成时间
      if (actualCompletionDates[previousIndex]) {
        // 使用实际完成时间作为下一个节点的开始时间
        cumulativeStartTime = new Date(actualCompletionDates[previousIndex]!);
        console.log(`节点 ${previousIndex} 使用实际完成时间: ${formatDate(cumulativeStartTime)}`);
      } else {
        // 使用预计完成时间
        cumulativeStartTime = new Date(previousResult.estimatedEnd);
      }
    }
    
    // 只重新计算从第一个调整节点开始的后续节点
    for (let i = firstAdjustedIndex; i < updatedResults.length; i++) {
      const result = updatedResults[i];
      const baseTimelineValue = (typeof result.timelineValue === 'number')
        ? result.timelineValue
        : (typeof result.adjustedTimelineValue === 'number')
          ? result.adjustedTimelineValue
          : 0;
      const adjustment = adjustments[i] || 0;
      const adjustedTimelineValue = baseTimelineValue + adjustment;
      
      // 计算当前节点的开始时间
      let nodeStartTime = new Date(cumulativeStartTime);
      
      // 重新应用起始日期调整规则
      if (result.startDateRule) {
        let ruleJson = '';
        if (typeof result.startDateRule === 'string') {
          ruleJson = result.startDateRule;
        } else if (result.startDateRule && result.startDateRule.text) {
          ruleJson = result.startDateRule.text;
        }
        
        if (ruleJson.trim()) {
          nodeStartTime = adjustStartDateByRule(nodeStartTime, ruleJson);
        }
      }
      
      // 重新应用JSON格式日期调整规则
      let ruleDescription = result.ruleDescription; // 保持原有描述作为默认值
      if (result.dateAdjustmentRule) {
        let ruleText = '';
        if (typeof result.dateAdjustmentRule === 'string') {
          ruleText = result.dateAdjustmentRule;
        } else if (Array.isArray(result.dateAdjustmentRule)) {
          ruleText = result.dateAdjustmentRule
            .filter(item => item.type === 'text')
            .map(item => item.text)
            .join('');
        } else if (result.dateAdjustmentRule && result.dateAdjustmentRule.text) {
          ruleText = result.dateAdjustmentRule.text;
        }
        
        if (ruleText && ruleText.trim() !== '') {
          const adjustmentResult = adjustStartDateByJsonRule(nodeStartTime, ruleText);
          nodeStartTime = adjustmentResult.adjustedDate;
          // 更新规则描述
          if (adjustmentResult.description) {
            ruleDescription = adjustmentResult.description;
          }
        }
      }
      
      const nodeWeekendDays = result.weekendDaysConfig || []; // 使用节点特定的休息日配置
      const nodeCalculationMethod = result.calculationMethod || '外部'; // 获取节点的计算方式
      
      let nodeEndTime: Date;
      const nodeExcludedDates = Array.isArray(result.excludedDates) ? result.excludedDates : [];
      if (adjustedTimelineValue > 0) {
        const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates);
        if (nodeCalculationMethod === '内部') {
          nodeEndTime = addInternalBusinessTime(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        } else {
          nodeEndTime = addBusinessDaysWithHolidays(adjustedStartTime, adjustedTimelineValue, nodeWeekendDays, nodeExcludedDates);
        }
      } else {
        nodeEndTime = new Date(nodeStartTime);
      }
      
      // 计算跳过的天数
      const adjustedStartTime = adjustedTimelineValue > 0 ? adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, nodeWeekendDays, nodeExcludedDates) : nodeStartTime;
      const skippedWeekends = calculateSkippedWeekends(adjustedStartTime, nodeEndTime, nodeWeekendDays);
      const estimatedStartStr = formatDate(adjustedStartTime);
      const estimatedEndStr = adjustedTimelineValue > 0 ? formatDate(nodeEndTime) : '时效值为0';
      const actualDays = calculateActualDays(estimatedStartStr, estimatedEndStr);
      
      // 计算时间范围内实际跳过的自定义日期
      const excludedDatesInRange = calculateExcludedDatesInRange(adjustedStartTime, nodeEndTime, nodeExcludedDates);
      
      // 更新结果
        updatedResults[i] = {
          ...result,
          adjustedTimelineValue: adjustedTimelineValue,
          estimatedStart: estimatedStartStr,
          estimatedEnd: estimatedEndStr,
          adjustment: adjustment,
          calculationMethod: nodeCalculationMethod, // 保持计算方式
          skippedWeekends: skippedWeekends,
          actualDays: actualDays,
          // 更新时间范围内实际跳过的日期
          actualExcludedDates: excludedDatesInRange.dates,
          actualExcludedDatesCount: excludedDatesInRange.count,
          adjustmentDescription: result.adjustmentDescription, // 保持调整规则描述
          ruleDescription: ruleDescription // 添加更新后的规则描述
        };
      
      // 更新累积时间：优先使用当前节点的实际完成时间，否则使用预计完成时间
      if (adjustedTimelineValue > 0) {
        if (actualCompletionDates[i]) {
          // 如果当前节点有实际完成时间，使用实际完成时间
          cumulativeStartTime = new Date(actualCompletionDates[i]!);
        } else {
          // 否则使用预计完成时间
          cumulativeStartTime = new Date(nodeEndTime);
        }
      }
    }
    
    setTimelineResults(updatedResults);
  };

  // 添加快照还原状态标志
  const [isRestoringSnapshot, setIsRestoringSnapshot] = useState(false);

  // 当起始时间变更时，重新以最新起始时间为基准重算全流程
  useEffect(() => {
    if (timelineResults.length > 0 && !isRestoringSnapshot) {
      recalculateTimeline(timelineAdjustments, true); // 强制重算所有节点
    }
  }, [startTime, isRestoringSnapshot]);

  // 重置调整的函数
  const resetTimelineAdjustments = () => {
    setTimelineAdjustments({});
    setDeliveryMarginDeductions(0); // 同时重置交期余量扣减
    setCompletionDateAdjustment(0); // 重置最后流程完成日期调整
    setActualCompletionDates({}); // 重置实际完成日期
    recalculateTimeline({}, true); // 强制重算所有节点
  };
  
  // 已移除未使用的 getTimelineLabelFieldId 辅助函数

  // 写入货期记录表的函数
  const writeToDeliveryRecordTable = async (
    timelineResults: any[],
    processRecordIds: string[],
    timelineAdjustments: {[key: number]: number} = {},
    batchData?: {
      selectedRecords: string[],
      recordDetails: any[],
      labels?: Record<string, any>,
      expectedDate?: any,
      startTime?: any
    }
  ) => {
    try {
      console.log('=== 开始写入货期记录表 ===');
      console.log('当前模式:', mode);
      console.log('timelineResults数量:', timelineResults?.length || 0);
      console.log('processRecordIds数量:', processRecordIds?.length || 0);
      console.log('timelineAdjustments:', timelineAdjustments);
      console.log('timelineResults详情:', timelineResults);
      console.log('processRecordIds详情:', processRecordIds);
      
      // 获取货期记录表
      console.log('正在获取货期记录表...');
      const deliveryRecordTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
      console.log('成功获取货期记录表');
      
      // 检查字段是否存在
      console.log('正在检查和获取所有必需字段...');
      const fieldsToCheck = [
        DELIVERY_FOREIGN_ID_FIELD_ID,
        DELIVERY_LABELS_FIELD_ID,
        DELIVERY_STYLE_FIELD_ID,
        DELIVERY_COLOR_FIELD_ID,
        DELIVERY_CREATE_TIME_FIELD_ID,
        DELIVERY_EXPECTED_DATE_FIELD_ID,
        DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID,
        DELIVERY_NODE_DETAILS_FIELD_ID,
        DELIVERY_ADJUSTMENT_INFO_FIELD_ID,  // 添加货期调整信息字段
        DELIVERY_START_TIME_FIELD_ID        // 新增：起始时间字段
      ];
      console.log('需要检查的字段ID列表:', fieldsToCheck);
      
      // 获取各个字段
      console.log('正在获取各个字段对象...');
      const foreignIdField = await deliveryRecordTable.getField(DELIVERY_FOREIGN_ID_FIELD_ID);
      const labelsField = await deliveryRecordTable.getField(DELIVERY_LABELS_FIELD_ID);
      const styleField = await deliveryRecordTable.getField(DELIVERY_STYLE_FIELD_ID);
      const colorField = await deliveryRecordTable.getField(DELIVERY_COLOR_FIELD_ID);
      const text2Field = await deliveryRecordTable.getField(DELIVERY_TEXT2_FIELD_ID);
      const createTimeField = await deliveryRecordTable.getField(DELIVERY_CREATE_TIME_FIELD_ID);
      const expectedDateField = await deliveryRecordTable.getField(DELIVERY_EXPECTED_DATE_FIELD_ID);
      const nodeDetailsField = await deliveryRecordTable.getField(DELIVERY_NODE_DETAILS_FIELD_ID);
      const customerExpectedDateField = await deliveryRecordTable.getField(DELIVERY_CUSTOMER_EXPECTED_DATE_FIELD_ID);
      const adjustmentInfoField = await deliveryRecordTable.getField(DELIVERY_ADJUSTMENT_INFO_FIELD_ID);
      const versionField = await deliveryRecordTable.getField(DELIVERY_VERSION_FIELD_ID);
      const startTimeField = await deliveryRecordTable.getField(DELIVERY_START_TIME_FIELD_ID);
      const snapshotField = await deliveryRecordTable.getField(DELIVERY_SNAPSHOT_JSON_FIELD_ID);
      console.log('成功获取所有字段对象');
      
      // 检查标签汇总字段的类型
      console.log('标签汇总字段信息:', {
        id: labelsField.id,
        name: labelsField.name,
        type: labelsField.type,
        property: labelsField.property
      });
      
      // 获取foreign_id：调整模式严格使用快照数据，生成模式优先使用选择记录
      console.log('=== 开始获取foreign_id ===');
      let foreignId = '';
      
      // 使用传递的数据或全局状态
      const currentSelectedRecords = batchData?.selectedRecords || selectedRecords;
      const currentRecordDetails = batchData?.recordDetails || recordDetails;
      
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的foreign_id，即使为空也不回退
        foreignId = currentForeignId;
        console.log('调整模式：严格使用快照恢复的foreign_id:', foreignId);
      } else if (currentSelectedRecords.length > 0) {
        // 生成模式：从选择记录获取
        console.log('生成模式：从选择记录获取foreign_id');
        console.log('selectedRecords[0]:', currentSelectedRecords[0]);
        
        if (batchData) {
          // 批量模式：直接从传递的数据中获取
          const firstRecord = currentRecordDetails[0];
          if (firstRecord && firstRecord.fields && firstRecord.fields['fldpvBfeC0']) {
            const fieldValue = firstRecord.fields['fldpvBfeC0'];
            foreignId = extractText(fieldValue);
            console.log('批量模式：从传递数据获取foreign_id:', foreignId);
          }
        } else {
          // 生成模式：从数据库获取
          const table = await bitable.base.getTable(TABLE_ID);
          const firstRecord = await table.getRecordById(currentSelectedRecords[0]);
          console.log('获取到的记录:', firstRecord);
          const fieldValue = firstRecord.fields['fldpvBfeC0'];
          console.log('fldpvBfeC0字段值:', fieldValue);
          
          foreignId = extractText(fieldValue);
        }
      }
      
      // 生成模式的回退逻辑：记录详情
      if (mode !== 'adjust' && !foreignId && currentRecordDetails.length > 0) {
        const first = currentRecordDetails[0];
        const val = first.fields['fldpvBfeC0'];
        foreignId = extractText(val);
      }
      // 生成模式的最后回退：快照状态
      if (mode !== 'adjust' && !foreignId && currentForeignId) {
        foreignId = currentForeignId;
      }
      
      // 获取款式与颜色：调整模式优先使用快照数据，生成模式优先使用记录详情
      let style = '';
      let color = '';
      
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的数据，即使为空也不回退
        style = currentStyleText;
        color = currentColorText;
        console.log('调整模式：严格使用快照恢复的款式:', style, '颜色:', color);
      } else {
        // 生成模式：优先使用记录详情
        if (currentRecordDetails.length > 0) {
          const first = currentRecordDetails[0];
          style = extractText(first.fields['fld6Uw95kt']) || currentStyleText || '';
          color = extractText(first.fields['flde85ni4O']) || currentColorText || '';
        } else {
          // 回退：使用快照回填的状态
          style = currentStyleText || '';
          color = currentColorText || '';
          // 若仍为空且有选择记录，仅做一次读取
          if ((!style || !color) && currentSelectedRecords.length > 0) {
            const table = await bitable.base.getTable(TABLE_ID);
            const firstRecord = await table.getRecordById(currentSelectedRecords[0]);
            style = style || extractText(firstRecord.fields['fld6Uw95kt']);
            color = color || extractText(firstRecord.fields['flde85ni4O']);
          }
        }
      }
      
      // 获取文本2：调整模式优先使用快照数据；生成模式在批量模式下填写
      let text2 = '';
      if (mode === 'adjust') {
        // 调整模式：严格使用快照回填的数据，即使为空也不回退
        text2 = currentText2; // 直接使用快照值，不使用 || '' 的回退逻辑
        console.log('调整模式：严格使用快照恢复的文本2:', text2);
      } else {
        if (batchData && currentRecordDetails.length > 0) {
          const first = currentRecordDetails[0];
          if (first?.fields?.['fldG6LZnmU']) {
            text2 = extractText(first.fields['fldG6LZnmU']);
          }
          // 兜底：若批量数据中显式传递了text2，则使用之
          if (!text2 && (batchData as any).text2) {
            try { text2 = extractText((batchData as any).text2); } catch { text2 = (batchData as any).text2; }
          }
          console.log('生成模式（批量）：文本2来自批量数据:', text2);
        } else {
          // 非批量的生成模式：保持为空
          text2 = '';
          console.log('生成模式：文本2字段保持为空');
        }
      }
      
      // 获取标签汇总：批量模式优先使用传入的labels
      const selectedLabelValues = batchData?.labels
        ? Object.values(batchData.labels).flat().filter(Boolean)
        : Object.values(selectedLabels).flat().filter(Boolean);
      
      // 获取预计交付日期（交期余量的日期版本：最后流程完成日期 + 基础缓冲期）
      let expectedDeliveryDate = null;
      if (timelineResults.length > 0) {
        // 从后往前查找第一个有效的流程完成日期（与交期余量计算逻辑一致）
        let effectiveLastProcess = null;
        for (let i = timelineResults.length - 1; i >= 0; i--) {
          const process = timelineResults[i];
          if (process.estimatedEnd && 
              !process.estimatedEnd.includes('未找到') && 
              !process.estimatedEnd.includes('时效值为0') &&
              process.estimatedEnd !== 'Invalid Date') {
            effectiveLastProcess = process;
            break;
          }
        }
        
        if (effectiveLastProcess) {
          try {
            const lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
            
            // 计算动态缓冲期：基础缓冲期 - 节点总调整量，最小为0天
            const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
            const baseBuferDays = baseBufferDays;
            const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
            
            // 加上动态缓冲期
            const deliveryDate = new Date(lastCompletionDate);
            deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
            expectedDeliveryDate = deliveryDate.getTime();
          } catch (error) {
            console.error('转换预计交付日期失败:', error);
          }
        }
      }
      
      // 获取客户期望日期：批量模式优先使用传入的expectedDate
      let customerExpectedDate = null;
      if (batchData?.expectedDate) {
        try {
          customerExpectedDate = new Date(batchData.expectedDate).getTime();
        } catch { /* 忽略转换错误，保持null */ }
      } else if (expectedDate) {
        customerExpectedDate = expectedDate.getTime(); // 转换为时间戳
      }
      
      // 创建当前时间戳
      const currentTime = new Date().getTime();
      
      // 计算版本号（数字）并格式化货期调整信息
      let versionNumber = 1;
      try {
        if (mode === 'adjust' && currentVersionNumber !== null) {
          // 调整模式：优先使用快照version +1
          versionNumber = currentVersionNumber + 1;
        } else if (foreignId) {
          const existing = await deliveryRecordTable.getRecords({
            pageSize: 5000,
            filter: {
              conjunction: 'and',
              conditions: [{
                fieldId: DELIVERY_FOREIGN_ID_FIELD_ID,
                operator: 'is',
                value: [foreignId]
              }]
            }
          });
          const count = existing.records?.length || 0;
          versionNumber = count + 1;
        }
      } catch (e) {
        console.warn('计算版本号失败:', e);
      }

      let adjustmentInfo = `版本：V${versionNumber}`;
      if (Object.keys(timelineAdjustments).length > 0) {
        const adjustmentTexts = Object.entries(timelineAdjustments).map(([nodeIndex, adjustment]) => {
          const nodeName = timelineResults[parseInt(nodeIndex)]?.nodeName || `节点${parseInt(nodeIndex) + 1}`;
          return `${nodeName}: ${adjustment > 0 ? '+' : ''}${adjustment.toFixed(1)} 天`;
        });
        adjustmentInfo += `\n当前调整：\n${adjustmentTexts.join('\n')}`;
      }
      
      // 在创建Cell之前进行数据校验（移除冗余日志）

      // ===== 构建完整快照（保持与流程数据表写入时的一致内容）并写入到货期记录表 =====
      const expectedDateTimestamp = (batchData?.expectedDate || expectedDate)
        ? (batchData?.expectedDate || expectedDate).getTime()
        : null;
      const expectedDateString = (batchData?.expectedDate || expectedDate)
        ? format((batchData?.expectedDate || expectedDate), DATE_FORMATS.STORAGE_FORMAT)
        : null;
      const currentStartTime = batchData?.startTime || startTime;
      const currentSelectedLabels = batchData?.labels || selectedLabels;

      // 与快照字段保持相同的命名
      const styleText = style || '';
      const colorText = color || '';

      const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);

      // 检查是否达到最终限制
      let hasReachedFinalLimit = false;
      const currentExpectedDate = batchData?.expectedDate || expectedDate;
      if (dynamicBufferDays === 0 && currentExpectedDate && timelineResults.length > 0) {
        const lastNode = timelineResults[timelineResults.length - 1];
        if (lastNode && lastNode.estimatedEnd && !lastNode.estimatedEnd.includes('未找到')) {
          try {
            const lastCompletionDate = new Date(lastNode.estimatedEnd);
            const daysToExpected = Math.ceil((currentExpectedDate.getTime() - lastCompletionDate.getTime()) / (1000 * 60 * 60 * 24));
            hasReachedFinalLimit = daysToExpected <= 0;
          } catch (error) {
            console.warn('计算最终限制状态失败:', error);
          }
        }
      }

      const globalSnapshot = {
        version: versionNumber,
        foreignId,
        styleText,
        colorText,
        text2,
        mode,
        selectedLabels: currentSelectedLabels,
        expectedDateTimestamp,
        expectedDateString,
        startTimestamp: currentStartTime ? currentStartTime.getTime() : undefined,
        startString: currentStartTime ? formatDate(currentStartTime, 'STORAGE_FORMAT') : undefined,
        timelineAdjustments,
        generationModeState: {
          currentForeignId,
          currentStyleText,
          currentColorText,
          currentText2,
          currentVersionNumber: versionNumber,
          recordDetails: recordDetails || [],
          hasSelectedLabels: Object.values(selectedLabels).some(value => {
            return Array.isArray(value) ? value.length > 0 : Boolean(value);
          }),
          labelSelectionComplete: Object.keys(selectedLabels).length > 0
        },
        bufferManagement: {
          baseDays: baseBuferDays,
          totalAdjustments,
          dynamicBufferDays,
          hasReachedFinalLimit
        },
        chainAdjustmentSystem: {
          enabled: true,
          lastCalculationTime: new Date().getTime(),
          adjustmentHistory: timelineAdjustments
        },
        timelineCalculationState: {
          calculationTimestamp: new Date().getTime(),
          totalNodes: timelineResults.length,
          hasValidResults: timelineResults.length > 0,
          lastCalculationMode: mode
        },
        totalNodes: timelineResults.length,
        isGlobalSnapshot: true
      };

      // 选择用于快照的最后一个有效节点（与流程写入时的节点快照结构一致）
      let selectedIndex = -1;
      for (let i = timelineResults.length - 1; i >= 0; i--) {
        const r = timelineResults[i];
        if (r.estimatedEnd && !r.estimatedEnd.includes('未找到') && r.estimatedEnd.trim() !== '') {
          selectedIndex = i;
          break;
        }
      }
      if (selectedIndex === -1) selectedIndex = 0; // 无有效结束时间时兜底为第一个

      const selectedResult = timelineResults[selectedIndex];
      let nodeStartTs = null as number | null;
      let nodeEndTs = null as number | null;
      if (selectedResult.estimatedStart && !selectedResult.estimatedStart.includes('未找到')) {
        try { nodeStartTs = new Date(selectedResult.estimatedStart).getTime(); } catch {}
      }
      if (selectedResult.estimatedEnd && !selectedResult.estimatedEnd.includes('未找到')) {
        try { nodeEndTs = new Date(selectedResult.estimatedEnd).getTime(); } catch {}
      }

      const nodeSnapshot = {
        processOrder: selectedResult.processOrder,
        nodeName: selectedResult.nodeName,
        matchedLabels: selectedResult.matchedLabels,
        timelineValue: selectedResult.timelineValue,
        estimatedStart: selectedResult.estimatedStart,
        estimatedEnd: selectedResult.estimatedEnd,
        estimatedStartTimestamp: nodeStartTs,
        estimatedEndTimestamp: nodeEndTs,
        timelineRecordId: selectedResult.timelineRecordId,
        allMatchedRecords: selectedResult.allMatchedRecords,
        isAccumulated: selectedResult.isAccumulated,
        weekendDaysConfig: selectedResult.weekendDaysConfig,
        excludedDates: selectedResult.excludedDates,
        actualExcludedDates: selectedResult.actualExcludedDates,
        actualExcludedDatesCount: selectedResult.actualExcludedDatesCount,
        calculationMethod: selectedResult.calculationMethod,
        ruleDescription: selectedResult.ruleDescription,
        skippedWeekends: selectedResult.skippedWeekends,
        actualDays: selectedResult.actualDays,
        adjustedTimelineValue: selectedResult.adjustedTimelineValue,
        adjustment: selectedResult.adjustment,
        adjustmentDescription: selectedResult.adjustmentDescription,
        startDateRule: selectedResult.startDateRule,
        dateAdjustmentRule: selectedResult.dateAdjustmentRule,
        nodeCalculationState: {
          hasValidTimelineValue: selectedResult.timelineValue > 0,
          hasValidStartTime: Boolean(nodeStartTs),
          hasValidEndTime: Boolean(nodeEndTs),
          calculationTimestamp: new Date().getTime(),
          originalTimelineValue: selectedResult.timelineValue,
          finalAdjustedValue: selectedResult.adjustedTimelineValue || selectedResult.timelineValue
        },
        chainAdjustmentNode: {
          nodeIndex: selectedIndex,
          hasAdjustment: selectedResult.adjustment !== undefined && selectedResult.adjustment !== 0,
          adjustmentValue: selectedResult.adjustment || 0,
          isChainSource: selectedResult.adjustment !== undefined && selectedResult.adjustment !== 0,
          affectedByChain: selectedIndex > 0
        },
        isNodeSnapshot: true
      };

      const completeSnapshot = {
        ...globalSnapshot,
        ...nodeSnapshot,
        timelineResults: timelineResults,
        currentNodeIndex: selectedIndex,
        currentNodeName: selectedResult.nodeName,
        isCompleteSnapshot: true,
        snapshotType: 'complete'
      };
      const snapshotJson = JSON.stringify(completeSnapshot);

      // 使用createCell方法创建各个字段的Cell
      const foreignIdCell = await foreignIdField.createCell(foreignId);
      const labelsCell = selectedLabelValues.length > 0 ? await labelsField.createCell(selectedLabelValues) : null;
      const styleCell = await styleField.createCell(style);
      const colorCell = await colorField.createCell(color);
      const text2Cell = await text2Field.createCell(text2);
      const createTimeCell = await createTimeField.createCell(currentTime);
      
      // 调试日志：检查startTime参数
      console.log('批量模式 - startTime参数:', startTime);
      console.log('批量模式 - startTime类型:', typeof startTime);
      console.log('批量模式 - currentTime:', currentTime, '对应日期:', new Date(currentTime).toLocaleString());
      
      const startTimestamp = batchData?.startTime
        ? new Date(batchData.startTime).getTime()
        : (startTime ? startTime.getTime() : currentTime);
      console.log('批量模式 - 最终使用的startTimestamp:', startTimestamp, '对应日期:', new Date(startTimestamp).toLocaleString());
      
      const startTimeCell = await startTimeField.createCell(startTimestamp);
      const snapshotCell = await snapshotField.createCell(snapshotJson);
      const expectedDateCell = expectedDeliveryDate ? await expectedDateField.createCell(expectedDeliveryDate) : null;
      const customerExpectedDateCell = customerExpectedDate ? await customerExpectedDateField.createCell(customerExpectedDate) : null;
      // 对于关联记录字段，确保传入的是记录ID数组
      const nodeDetailsCell = processRecordIds.length > 0 ? 
        await nodeDetailsField.createCell({ recordIds: processRecordIds }) : null;
      // 创建货期调整信息Cell
      const adjustmentInfoCell = adjustmentInfo ? await adjustmentInfoField.createCell(adjustmentInfo) : null;
      // 创建版本号Cell（数字）
      const versionCell = await versionField.createCell(versionNumber);
      
      // 组合所有Cell到一个记录中
      const recordCells = [foreignIdCell, styleCell, colorCell, text2Cell, createTimeCell, startTimeCell, versionCell, snapshotCell];
      
      // 只有当数据存在时才添加对应的Cell
      if (labelsCell) recordCells.push(labelsCell);
      if (expectedDateCell) recordCells.push(expectedDateCell);
      if (customerExpectedDateCell) recordCells.push(customerExpectedDateCell);
      if (nodeDetailsCell) recordCells.push(nodeDetailsCell);
      if (adjustmentInfoCell) recordCells.push(adjustmentInfoCell);
      
      // 添加记录到货期记录表
      const addedRecord = await deliveryRecordTable.addRecord(recordCells);
      
      return addedRecord;
    } catch (error) {
      console.error('写入货期记录表详细错误:', {
        error: error,
        message: error.message,
        stack: error.stack,
        recordCellsLength: typeof recordCells !== 'undefined' ? recordCells.length : 'recordCells未定义'
      });
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '写入货期记录表失败: ' + (error as Error).message
        });
      }
      throw error;
    }
  };

  // 写入流程数据表的函数
  const writeToProcessDataTable = async (timelineResults: any[], batchData?: {
    selectedRecords: string[], 
    recordDetails: any[], 
    labels?: Record<string, any>, 
    expectedDate?: any, 
    startTime?: any
  }): Promise<string[]> => {
    try {
      console.log('=== 开始写入流程数据表 ===');
      console.log('当前模式:', mode);
      console.log('timelineResults数量:', timelineResults?.length || 0);
      console.log('timelineResults详情:', timelineResults);
      
      // 获取流程数据表和流程配置表
      console.log('正在获取流程数据表和流程配置表...');
      const processDataTable = await bitable.base.getTable(PROCESS_DATA_TABLE_ID);
      const processConfigTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      console.log('成功获取数据表');
      
      // 获取所有需要的字段
      console.log('正在获取所有必需字段...');
      const foreignIdField = await processDataTable.getField(FOREIGN_ID_FIELD_ID);
      const processNameField = await processDataTable.getField(PROCESS_NAME_FIELD_ID);
      const processOrderField = await processDataTable.getField(PROCESS_ORDER_FIELD_ID_DATA);
      const startDateField = await processDataTable.getField(ESTIMATED_START_DATE_FIELD_ID);
      const endDateField = await processDataTable.getField(ESTIMATED_END_DATE_FIELD_ID);
      const versionField = await processDataTable.getField(PROCESS_VERSION_FIELD_ID);
      const timelinessField = await processDataTable.getField(PROCESS_TIMELINESS_FIELD_ID);
      console.log('成功获取所有字段');
      
      // 获取foreign_id - 支持批量模式直接传递数据
      console.log('=== 开始获取foreign_id ===');
      let foreignId = null;
      
      // 使用传递的数据或全局状态
      const currentSelectedRecords = batchData?.selectedRecords || selectedRecords;
      const currentRecordDetails = batchData?.recordDetails || recordDetails;
      
      console.log('selectedRecords数量:', currentSelectedRecords?.length || 0);
      console.log('recordDetails数量:', currentRecordDetails?.length || 0);
      console.log('selectedRecords:', currentSelectedRecords);
      console.log('recordDetails:', currentRecordDetails);
      
      if (currentSelectedRecords.length > 0 && currentRecordDetails.length > 0) {
        // 从第一个选择的记录的详情中获取fldpvBfeC0字段的值
        const firstRecord = currentRecordDetails[0];
        if (firstRecord && firstRecord.fields && firstRecord.fields['fldpvBfeC0']) {
          const fieldValue = firstRecord.fields['fldpvBfeC0'];
          foreignId = extractText(fieldValue);
          console.log('从fldpvBfeC0字段获取到的foreign_id:', foreignId);
        } else {
          console.warn('未在记录详情中找到fldpvBfeC0字段');
          console.log('第一个记录的字段:', firstRecord?.fields);
        }
      }
      
      // 快照回填：在调整模式通过快照还原时使用当前foreign_id状态
      if (!foreignId && currentForeignId) {
        foreignId = currentForeignId;
        console.log('使用快照恢复的foreign_id:', foreignId);
      }
      
      if (!foreignId) {
        console.warn('未找到foreign_id，跳过写入流程数据表');
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '未找到foreign_id字段，无法写入流程数据表'
          });
        }
        return [];
      }
      
      // 先删除该foreign_id的所有现有记录
      console.log('=== 开始删除现有记录 ===');
      console.log('使用的foreign_id:', foreignId);
      try {
        console.log('正在查询现有记录...');
        const existingRecords = await processDataTable.getRecords({
          pageSize: 5000,
          filter: {
            conjunction: 'And',
            conditions: [{
              fieldId: FOREIGN_ID_FIELD_ID,
              operator: 'is',
              value: [actualForeignId]
            }]
          }
        });
        
        console.log('查询到现有记录数量:', existingRecords.records?.length || 0);
        
        if (existingRecords.records && existingRecords.records.length > 0) {
          const recordIdsToDelete = existingRecords.records.map(record => record.id);
          console.log('准备删除的记录ID:', recordIdsToDelete);
          await processDataTable.deleteRecords(recordIdsToDelete);
          console.log(`成功删除 ${recordIdsToDelete.length} 条现有记录`);
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'info',
              message: `已删除 ${recordIdsToDelete.length} 条现有流程数据`
            });
          }
        } else {
          console.log('没有找到需要删除的现有记录');
        }
      } catch (deleteError) {
        console.error('删除现有记录时出错:', deleteError);
        // 继续执行，不中断流程
      }
      
      // 构建页面快照JSON（确保可一模一样还原）
      // 计算版本号：数字。默认按 foreign_id 在货期记录表的记录数量 + 1
      let versionNumber = 1;
      try {
        const deliveryRecordTable = await bitable.base.getTable(DELIVERY_RECORD_TABLE_ID);
        if (mode === 'adjust' && currentVersionNumber !== null) {
          // 调整模式：优先使用快照version +1，避免公式字段读取错误
          versionNumber = currentVersionNumber + 1;
        } else if (foreignId) {
          const existing = await deliveryRecordTable.getRecords({
            pageSize: 5000,
            filter: {
              conjunction: 'and',
              conditions: [{
                fieldId: DELIVERY_FOREIGN_ID_FIELD_ID,
                operator: 'is',
                value: [foreignId]
              }]
            }
          });
          const count = existing.records?.length || 0;
          versionNumber = count + 1;
        }
      } catch (e) {
        console.warn('计算版本号失败:', e);
      }


      // 使用createCell方法准备要写入的记录数据
        const recordCellsToAdd = [];
        
        for (let index = 0; index < timelineResults.length; index++) {
          const result = timelineResults[index];
          console.log('处理节点数据:', result);
          
          // 检查是否有有效的预计完成时间（只检查结束时间）
          const hasValidEndTime = (
            result.estimatedEnd && 
            !result.estimatedEnd.includes('未找到') && 
            result.estimatedEnd.trim() !== ''
          );
          
          // 如果没有有效的预计完成时间，跳过这个节点
          if (!hasValidEndTime) {
            console.log(`跳过节点 "${result.nodeName}" - 未找到有效的预计完成时间`);
            continue;
          }
          
          // 转换日期格式为时间戳（毫秒）
          let startTimestamp = null;
          let endTimestamp = null;
          
          if (result.estimatedStart && !result.estimatedStart.includes('未找到')) {
            try {
              startTimestamp = new Date(result.estimatedStart).getTime();
            } catch (error) {
              console.error(`转换开始时间失败:`, error);
            }
          }
          
          if (result.estimatedEnd && !result.estimatedEnd.includes('未找到')) {
            try {
              endTimestamp = new Date(result.estimatedEnd).getTime();
            } catch (error) {
              console.error(`转换结束时间失败:`, error);
            }
          }
          
          
          // 使用createCell方法创建每个字段的Cell
          const foreignIdCell = await foreignIdField.createCell(foreignId);
          // 直接使用节点名称创建单元格
          const processNameCell = await processNameField.createCell(result.nodeName);
          const processOrderCell = await processOrderField.createCell(result.processOrder);
          const startDateCell = startTimestamp ? await startDateField.createCell(startTimestamp) : null;
          const endDateCell = endTimestamp ? await endDateField.createCell(endTimestamp) : null;
          
          // 组合所有Cell到一个记录中
          const versionCell = await versionField.createCell(versionNumber);
          const timelinessCell = (typeof result.timelineValue === 'number')
            ? await timelinessField.createCell(result.timelineValue)
            : null;
          const recordCells = [
            foreignIdCell,
            processNameCell,
            processOrderCell,
            versionCell
          ];
          
          // 只有当时间戳存在时才添加日期Cell
          if (startDateCell) recordCells.push(startDateCell);
          if (endDateCell) recordCells.push(endDateCell);
          if (timelinessCell) recordCells.push(timelinessCell);
          
          console.log(`准备写入的Cell记录 - ${result.nodeName}:`, recordCells);
          recordCellsToAdd.push(recordCells);
        }
      
      console.log('所有准备写入的Cell记录:', recordCellsToAdd);
      
      // 在添加记录的部分，收集记录ID
      const addedRecordIds: string[] = [];
      
      if (recordCellsToAdd.length > 0) {
        try {
          // 使用addRecords进行批量写入
          const addedRecords = await processDataTable.addRecords(recordCellsToAdd);
          // 直接使用返回值，不需要map操作
          addedRecordIds.push(...addedRecords);
          console.log(`批量写入成功，记录ID:`, addedRecords);
        } catch (error) {
          console.error('批量写入失败，尝试逐条写入:', error);
          // 如果批量写入失败，回退到逐条写入
          for (const recordCells of recordCellsToAdd) {
            const addedRecord = await processDataTable.addRecord(recordCells);
            addedRecordIds.push(addedRecord);
            console.log('成功添加记录:', addedRecord);
          }
        }
        
        console.log(`成功写入 ${addedRecordIds.length} 条流程数据`);
        
        // 显示成功提示
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'success',
            message: `成功写入 ${addedRecordIds.length} 条流程数据到流程数据表`
          });
        }
        
        return addedRecordIds; // 返回记录ID列表
      } else {
        console.warn('没有有效的记录可以写入');
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: '没有有效的流程数据可以写入 - 所有节点都缺少时效数据'
          });
        }
        return [];
      }
      
    } catch (error) {
      console.error('写入流程数据表失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `写入流程数据表失败: ${(error as Error).message}`
        });
      }
      return [];
    }
  };

  // 批量处理函数
  // 批量模式：模拟生成模式的操作（简化版本）
  const simulateGenerationModeForBatch = async (
    recordId: string,
    extractedLabels: {[key: string]: string | string[]},
    extractedStartTime: Date | null,
    extractedExpectedDate: Date | null,
    style: any,
    color: any,
    foreignId: any,
    text2: any
  ) => {
    console.log('=== 批量模式：模拟生成模式操作 ===');
    console.log('recordId:', recordId);
    console.log('extractedLabels:', extractedLabels);
    console.log('extractedStartTime:', extractedStartTime);
    console.log('extractedExpectedDate:', extractedExpectedDate);
    
    // 1. 构造虚拟的 selectedRecords 和 recordDetails
    const virtualSelectedRecords = [recordId];
    const virtualRecordDetails = [{
      id: recordId,
      fields: {
        'fldpvBfeC0': foreignId, // 外键ID字段
        'fld6Uw95kt': style,     // 样式字段
        'flde85ni4O': color,     // 颜色字段
        'fldG6LZnmU': text2      // 文本字段2
      }
    }];
    
    try {
      // 不再设置全局状态，直接通过overrideData传递数据
      console.log('批量模式：直接调用计算逻辑，传递起始时间:', extractedStartTime);
      
      // 3. 直接调用时效计算，通过overrideData传递所有必要数据
      const calculatedResults = await handleCalculateTimeline(true, {
        selectedRecords: virtualSelectedRecords,
        recordDetails: virtualRecordDetails,
        selectedLabels: extractedLabels,
        expectedDate: extractedExpectedDate,
        startTime: extractedStartTime // 直接传递起始时间，避免异步状态更新问题
      }, false); // showUI: false，批量模式下不显示时间轴UI
      
      console.log('批量模式：时效计算完成，结果:', calculatedResults);
      
      // 批量模式：更新UI显示最后处理记录的时间设置
      console.log('批量模式：更新UI显示时间设置');
      setExpectedDate(extractedExpectedDate);
      setStartTime(extractedStartTime);
      
      // 批量模式：自动保存逻辑
      console.log('批量模式：开始自动保存流程');
      
      // 检查计算结果
      if (!calculatedResults || calculatedResults.length === 0) {
        console.error('批量模式：时效计算结果为空，无法保存');
        throw new Error('时效计算结果为空，请检查流程配置和标签匹配');
      }
      
      // 自动触发保存
      console.log('批量模式：开始自动保存数据');
      await saveTimelineData({
        timelineResults: calculatedResults, // 使用直接返回的结果
        selectedRecords: virtualSelectedRecords,
        recordDetails: virtualRecordDetails,
        timelineAdjustments: {}, // 批量模式下没有手动调整
        labels: extractedLabels,
        expectedDate: extractedExpectedDate,
        startTime: extractedStartTime
      });
      
      console.log('批量模式：自动保存完成');
      
    } catch (error) {
      console.error('批量模式：处理失败', error);
      throw error; // 重新抛出错误让上层处理
    }
  };

  // 保存时效数据的核心逻辑（从确定并保存按钮提取）
  const saveTimelineData = async (batchData?: {
    timelineResults?: any[],
    selectedRecords?: string[],
    recordDetails?: any[],
    timelineAdjustments?: any,
    labels?: Record<string, any>, // 添加标签汇总
    expectedDate?: any, // 添加期望日期
    startTime?: any // 添加起始时间
  }) => {
    try {
      // 使用传入的数据或全局状态
      const currentTimelineResults = batchData?.timelineResults || timelineResults;
      const currentTimelineAdjustments = batchData?.timelineAdjustments || timelineAdjustments;
      
      if (currentTimelineResults.length > 0) {
        // 构造批量数据参数
        const batchDataForWriting = batchData ? {
          selectedRecords: batchData.selectedRecords || [],
          recordDetails: batchData.recordDetails || [],
          labels: batchData.labels, // 传递标签汇总
          expectedDate: batchData.expectedDate, // 传递期望日期
          startTime: batchData.startTime // 传递起始时间
        } : undefined;
        
        // 写入流程数据表
        const processRecordIds = await writeToProcessDataTable(currentTimelineResults, batchDataForWriting);
        
        // 写入货期记录表
        await writeToDeliveryRecordTable(currentTimelineResults, processRecordIds, currentTimelineAdjustments, batchDataForWriting);
        
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'success',
            message: Object.keys(currentTimelineAdjustments).length > 0 
              ? '已保存调整后的时效数据到流程数据表和货期记录表' 
              : '已保存计算的时效数据到流程数据表和货期记录表'
          });
        }
        
        return true; // 保存成功
      }
      return false; // 没有数据需要保存
    } catch (error) {
      console.error('保存数据时出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '保存数据失败，请重试'
        });
      }
      throw error; // 重新抛出错误
    }
  };

  const handleBatchProcess = async (rowCount: number) => {
    // 切换到批量处理流程时重置全局变量
    resetGlobalState();
    // 检查是否选择了表
    if (!selectedBatchTableId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'warning',
          message: '请先选择要处理的数据表'
        });
      }
      return;
    }
    
    setBatchProcessing(true);
    setBatchProgress({ current: 0, total: rowCount });
    
    try {
      // 使用选择的表而不是硬编码的表ID
      const batchTable = await bitable.base.getTable(selectedBatchTableId);
      
      // 获取表中的记录（限制数量）
      let records = [];
      if (selectedBatchViewId) {
        // 如果选择了视图，从视图中获取记录ID列表，然后获取记录
        const view = await batchTable.getViewById(selectedBatchViewId);
        const recordIdList = await view.getVisibleRecordIdList();
        const limitedRecordIds = recordIdList.slice(0, rowCount).filter(id => id !== undefined);
        
        // 批量获取记录
        for (const recordId of limitedRecordIds) {
          try {
            const record = await batchTable.getRecordById(recordId);
            // 将recordId添加到记录对象中，确保记录对象包含正确的ID
            record.recordId = recordId;
            records.push(record);
          } catch (error) {
            console.warn(`Failed to get record ${recordId}:`, error);
          }
        }
      } else {
        // 如果没有选择视图，从表中获取记录
        const recordsResult = await batchTable.getRecords({
          pageSize: rowCount
        });
        records = recordsResult.records || [];
      }
      const actualCount = Math.min(records.length, rowCount);
      
      if (actualCount === 0) {
        if (bitable.ui.showToast) {
          await bitable.ui.showToast({
            toastType: 'warning',
            message: selectedBatchViewId ? '选择的视图中没有找到记录' : '选择的表中没有找到记录'
          });
        }
        return;
      }
      
      setBatchProgress({ current: 0, total: actualCount });
      
      // 获取新表的字段映射
      const fieldMetaList = await batchTable.getFieldMetaList();
      const fieldMapping: {[key: string]: string} = {};
      const optionMapping: {[fieldId: string]: {[optionId: string]: string}} = {};
      
      // 建立字段映射和选项映射
      for (const fieldMeta of fieldMetaList) {
        if (fieldMeta.name.match(/^标签([1-9]|10)$/)) {
          fieldMapping[fieldMeta.name] = fieldMeta.id;
          
          // 如果是选择字段，建立选项ID到名称的映射
          if (fieldMeta.property && fieldMeta.property.dataType && fieldMeta.property.dataType.property && fieldMeta.property.dataType.property.options) {
            optionMapping[fieldMeta.id] = {};
            for (const option of fieldMeta.property.dataType.property.options) {
              if (option.id && option.name) {
                optionMapping[fieldMeta.id][option.id] = option.name;
              }
            }
          }
        } else if (fieldMeta.name === '起始日期') {
          fieldMapping['起始日期'] = fieldMeta.id;
        } else if (fieldMeta.name === '客户期望日期') {
          fieldMapping['客户期望日期'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldGSdZgMI') {
          // 根据字段ID直接映射起始时间字段
          fieldMapping['起始时间'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldczh2nty') {
          // 款式字段映射
          fieldMapping['款式'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldk5fVYvW') {
          // 颜色字段映射
          fieldMapping['颜色'] = fieldMeta.id;
        } else if (fieldMeta.id === 'fldkKZecSv') {
          // foreign_id字段映射
          fieldMapping['foreign_id'] = fieldMeta.id;
        } else if (fieldMeta.name === 'oms看板record_id' ||  fieldMeta.id === 'fldlaYgpYO') {
          // 文本2字段映射 - 支持有空格和无空格的字段名称，以及直接ID匹配
          fieldMapping['文本2'] = fieldMeta.id;
        }
      }
      
      console.log('字段映射:', fieldMapping);
      console.log('选项映射:', optionMapping);
      console.log('所有字段元数据:', fieldMetaList.map(f => ({ id: f.id, name: f.name })));
      
      // 特别检查文本2字段
      const text2Fields = fieldMetaList.filter(f => f.name.includes('文本') || f.id === 'fldlaYgpYO');
      console.log('包含"文本"的字段或fldlaYgpYO:', text2Fields.map(f => ({ id: f.id, name: f.name })));
      
      let successCount = 0;
      let errorCount = 0;
      const errors: string[] = [];
      
      // 跟踪最后成功处理的记录的时间信息
      let lastSuccessfulStartTime: Date | null = null;
      let lastSuccessfulExpectedDate: Date | null = null;
      
      // 逐条处理记录
      for (let i = 0; i < actualCount; i++) {
        const record = records[i];
        setBatchProgress({ current: i + 1, total: actualCount });
        
        try {
          // 获取记录ID - 现在应该能正确获取到recordId
          const recordId = record.recordId || record.id || `record_${i + 1}`;
          console.log(`处理第 ${i + 1} 条记录:`, recordId);
          console.log(`记录对象结构:`, record);
          
          // 从记录中提取标签数据
          const extractedLabels: {[key: string]: string | string[]} = {};
          const recordFields = record.fields;
          
          // 提取标签1-10
          for (let labelNum = 1; labelNum <= 10; labelNum++) {
            const labelKey = `标签${labelNum}`;
            const fieldId = fieldMapping[labelKey];
            
            if (fieldId && recordFields[fieldId]) {
              const fieldValue = recordFields[fieldId];
              
              // 处理不同类型的字段值
              if (Array.isArray(fieldValue)) {
                // 多选字段或选项ID数组
                const values = fieldValue.map((item: any) => {
                  if (typeof item === 'string') {
                    // 如果是选项ID，从选项映射中查找对应的名称
                    if (optionMapping[fieldId] && optionMapping[fieldId][item]) {
                      return optionMapping[fieldId][item];
                    }
                    return item;
                  }
                  if (item && item.text) return item.text;
                  if (item && item.name) return item.name;
                  return '';
                }).filter(v => v);
                
                if (values.length > 0) {
                  // 处理可能包含逗号分隔的复合标签值，并与生成模式保持一致
                  const expandedValues: string[] = [];
                  values.forEach(value => {
                    if (typeof value === 'string' && value.includes(',')) {
                      // 拆分逗号分隔的值
                      const splitValues = value.split(',').map(v => v.trim()).filter(v => v !== '');
                      expandedValues.push(...splitValues);
                    } else {
                      expandedValues.push(value);
                    }
                  });
                  
                  // 与生成模式保持一致：单值返回字符串，多值返回数组
                  // 特殊处理：标签7始终返回数组结构
                  if (labelKey === '标签7') {
                    extractedLabels[labelKey] = expandedValues;
                  } else {
                    extractedLabels[labelKey] = expandedValues.length === 1 ? expandedValues[0] : expandedValues;
                  }
                }
              } else if (typeof fieldValue === 'string') {
                // 单行文本或选项ID
                let finalValue: string;
                if (optionMapping[fieldId] && optionMapping[fieldId][fieldValue]) {
                  finalValue = optionMapping[fieldId][fieldValue];
                } else {
                  finalValue = fieldValue;
                }
                
                // 特殊处理：标签7始终返回数组结构
                if (labelKey === '标签7') {
                  extractedLabels[labelKey] = [finalValue];
                } else {
                  extractedLabels[labelKey] = finalValue;
                }
              } else if (fieldValue && fieldValue.text) {
                // 富文本等
                const textValue = fieldValue.text;
                // 特殊处理：标签7始终返回数组结构
                if (labelKey === '标签7') {
                  extractedLabels[labelKey] = [textValue];
                } else {
                  extractedLabels[labelKey] = textValue;
                }
              } else if (fieldValue && typeof fieldValue === 'object') {
                // 处理公式字段和其他复杂对象
                if (fieldValue.value !== undefined) {
                  // 公式字段通常有value属性
                  if (Array.isArray(fieldValue.value)) {
                    const values = fieldValue.value.map((item: any) => {
                      if (typeof item === 'string') return item;
                      if (item && item.text) return item.text;
                      if (item && item.name) return item.name; // 处理选项的name属性
                      return '';
                    }).filter(v => v);
                    
                    if (values.length > 0) {
                      // 与生成模式保持一致：单值返回字符串，多值返回数组
                      // 特殊处理：标签7始终返回数组结构
                      if (labelKey === '标签7') {
                        extractedLabels[labelKey] = values;
                      } else {
                        extractedLabels[labelKey] = values.length === 1 ? values[0] : values;
                      }
                    }
                  } else if (typeof fieldValue.value === 'string') {
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [fieldValue.value];
                    } else {
                      extractedLabels[labelKey] = fieldValue.value;
                    }
                  } else if (fieldValue.value && fieldValue.value.name) {
                    // 单选字段的选项对象
                    const nameValue = fieldValue.value.name;
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [nameValue];
                    } else {
                      extractedLabels[labelKey] = nameValue;
                    }
                  }
                } else if (fieldValue.displayValue !== undefined) {
                  // 有些字段使用displayValue
                  if (Array.isArray(fieldValue.displayValue)) {
                    const values = fieldValue.displayValue.map((item: any) => {
                      if (typeof item === 'string') return item;
                      if (item && item.text) return item.text;
                      if (item && item.name) return item.name; // 处理选项的name属性
                      return '';
                    }).filter(v => v);
                    
                    if (values.length > 0) {
                      // 与生成模式保持一致：单值返回字符串，多值返回数组
                      // 特殊处理：标签7始终返回数组结构
                      if (labelKey === '标签7') {
                        extractedLabels[labelKey] = values;
                      } else {
                        extractedLabels[labelKey] = values.length === 1 ? values[0] : values;
                      }
                    }
                  } else if (typeof fieldValue.displayValue === 'string') {
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [fieldValue.displayValue];
                    } else {
                      extractedLabels[labelKey] = fieldValue.displayValue;
                    }
                  } else if (fieldValue.displayValue && fieldValue.displayValue.name) {
                    // 单选字段的选项对象
                    const nameValue = fieldValue.displayValue.name;
                    // 特殊处理：标签7始终返回数组结构
                    if (labelKey === '标签7') {
                      extractedLabels[labelKey] = [nameValue];
                    } else {
                      extractedLabels[labelKey] = nameValue;
                    }
                  }
                } else if (fieldValue.name) {
                  // 直接的选项对象，有name属性
                  const nameValue = fieldValue.name;
                  // 特殊处理：标签7始终返回数组结构
                  if (labelKey === '标签7') {
                    extractedLabels[labelKey] = [nameValue];
                  } else {
                    extractedLabels[labelKey] = nameValue;
                  }
                }
              }
            }
          }
          
          // 提取起始日期
          let extractedStartTime: Date | null = null;
          const startDateFieldId = fieldMapping['起始日期'] || fieldMapping['起始时间'];
          if (startDateFieldId && recordFields[startDateFieldId]) {
            const startDateValue = recordFields[startDateFieldId];
            if (typeof startDateValue === 'number') {
              extractedStartTime = new Date(startDateValue);
            } else if (typeof startDateValue === 'string') {
              extractedStartTime = new Date(startDateValue);
            } else if (Array.isArray(startDateValue) && startDateValue.length > 0) {
              // 处理数组格式的时间戳，如 [1757260800000]
              const timestamp = startDateValue[0];
              if (typeof timestamp === 'number') {
                extractedStartTime = new Date(timestamp);
              }
            }
          }
          
          // 提取客户期望日期
          let extractedExpectedDate: Date | null = null;
          const expectedDateFieldId = fieldMapping['客户期望日期'];
          if (expectedDateFieldId && recordFields[expectedDateFieldId]) {
            const expectedDateValue = recordFields[expectedDateFieldId];
            if (typeof expectedDateValue === 'number') {
              extractedExpectedDate = new Date(expectedDateValue);
            } else if (typeof expectedDateValue === 'string') {
              extractedExpectedDate = new Date(expectedDateValue);
            } else if (Array.isArray(expectedDateValue) && expectedDateValue.length > 0) {
              // 处理数组格式的时间戳，如 [1757260800000]
              const timestamp = expectedDateValue[0];
              if (typeof timestamp === 'number') {
                extractedExpectedDate = new Date(timestamp);
              }
            }
          }
          
          // 统一的字段提取函数（复用生成模式的逻辑）
          // 将提取的文本转换为富文本格式
          const createRichTextFormat = (text: string) => {
            return text ? [{ type: "text", text: text }] : null;
          };
          
          // 提取款式、颜色、foreign_id字段
          let extractedStyle: any = null;
          let extractedColor: any = null;
          let extractedForeignId: any = null;
          
          // 提取款式字段
          const styleFieldId = fieldMapping['款式'];
          if (styleFieldId && recordFields[styleFieldId]) {
            const styleText = extractText(recordFields[styleFieldId]);
            extractedStyle = createRichTextFormat(styleText);
          }
          
          // 提取颜色字段
          const colorFieldId = fieldMapping['颜色'];
          if (colorFieldId && recordFields[colorFieldId]) {
            const colorText = extractText(recordFields[colorFieldId]);
            extractedColor = createRichTextFormat(colorText);
          }
          
          // 提取foreign_id字段
          const foreignIdFieldId = fieldMapping['foreign_id'];
          if (foreignIdFieldId && recordFields[foreignIdFieldId]) {
            const foreignIdText = extractText(recordFields[foreignIdFieldId]);
            extractedForeignId = createRichTextFormat(foreignIdText);
          }
          
          // 提取文本2字段
          let extractedText2: any = null;
          const text2FieldId = fieldMapping['文本2'];
          console.log('文本2字段映射:', { fieldName: '文本2', fieldId: text2FieldId });
          console.log('记录字段keys:', Object.keys(recordFields));
          console.log('fldlaYgpYO字段值:', recordFields['fldlaYgpYO']);
          
          if (text2FieldId && recordFields[text2FieldId]) {
            extractedText2 = extractText(recordFields[text2FieldId]);
            console.log('提取后的extractedText2:', extractedText2);
          } else {
            console.log('文本2字段未找到或无数据:', { 
              fieldId: text2FieldId, 
              hasField: !!recordFields[text2FieldId],
              fieldValue: recordFields[text2FieldId]
            });
          }

          console.log(`记录 ${i + 1} 提取的数据:`, {
            labels: extractedLabels,
            startTime: extractedStartTime,
            expectedDate: extractedExpectedDate,
            style: extractedStyle,
            color: extractedColor,
            foreignId: extractedForeignId,
            text2: extractedText2
          });
          
          console.log(`记录 ${i + 1} 字段映射:`, fieldMapping);
          console.log(`记录 ${i + 1} 记录字段:`, Object.keys(recordFields));
          
          // 如果没有提取到任何标签，跳过这条记录
          if (Object.keys(extractedLabels).length === 0) {
            console.warn(`记录 ${i + 1} 没有找到任何标签数据，跳过处理`);
            errorCount++;
            errors.push(`记录 ${i + 1}: 没有找到标签数据`);
            continue;
          }
          
          // 使用模拟生成模式的方式进行时效计算和写入
          await simulateGenerationModeForBatch(
            recordId, 
            extractedLabels, 
            extractedStartTime, 
            extractedExpectedDate, 
            extractedStyle, 
            extractedColor, 
            extractedForeignId, 
            extractedText2
          );
          
          successCount++;
          
          // 记录最后成功处理的记录的时间信息
          lastSuccessfulStartTime = extractedStartTime;
          lastSuccessfulExpectedDate = extractedExpectedDate;
          
          // 添加延迟避免API限制
          if (i < actualCount - 1) {
            await new Promise(resolve => setTimeout(resolve, 100));
          }
          
        } catch (error) {
          console.error(`处理记录 ${i + 1} 失败:`, error);
          errorCount++;
          errors.push(`记录 ${i + 1}: ${(error as Error).message}`);
        }
      }
      
      // 显示处理结果
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: successCount > 0 ? 'success' : 'error',
          message: `批量处理完成！成功: ${successCount} 条，失败: ${errorCount} 条`
        });
      }
      
      // 如果有成功处理的记录，更新UI时间显示为最后一条成功记录的时间
      if (successCount > 0 && lastSuccessfulStartTime && lastSuccessfulExpectedDate) {
        console.log('批量处理完成：更新UI时间显示');
        console.log('最后成功记录的起始时间:', lastSuccessfulStartTime);
        console.log('最后成功记录的期望日期:', lastSuccessfulExpectedDate);
        
        setStartTime(lastSuccessfulStartTime);
        setExpectedDate(lastSuccessfulExpectedDate);
      }
      
      if (errors.length > 0) {
        console.error('批量处理错误详情:', errors);
      }
      
    } catch (error) {
      console.error('批量处理失败:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `批量处理失败: ${(error as Error).message}`
        });
      }
    } finally {
      setBatchProcessing(false);
      setBatchProgress({ current: 0, total: 0 });
    }
  };

  // 为批量处理优化的时效计算函数
  const calculateTimelineForBatch = async (
    labels: {[key: string]: string | string[]}, 
    startTime: Date | null, 
    expectedDate: Date | null,
    sourceRecordId: string,
    style?: any,
    color?: any,
    foreignId?: any,
    text2?: any
  ) => {
    try {
      // 批量模式：输出当前数据结构，便于与生成模式对比
      try {
        console.group('=== 批量模式：计算时效 - 当前数据结构 ===');
        console.log('sourceRecordId:', sourceRecordId);
        console.log('labels:', labels);
        console.log('startTime:', startTime);
        console.log('expectedDate:', expectedDate);
        console.log('style:', style);
        console.log('color:', color);
        console.log('foreignId:', foreignId);
        console.log('text2:', text2);
        console.groupEnd();
      } catch (logErr) {
        console.warn('批量模式结构化日志输出失败:', logErr);
      }
      // 1. 获取流程配置表数据
      const processConfigTable = await bitable.base.getTable(PROCESS_CONFIG_TABLE_ID);
      const processConfigRecords = await processConfigTable.getRecords({
        pageSize: 5000
      });
      
      const processNodes = processConfigRecords.records || [];
      
      // 2. 构建业务选择的标签值集合
      const businessLabelValues = new Set<string>();
      console.log('批量模式 - 开始处理标签数据:', labels);
      
      for (const [labelKey, selectedValue] of Object.entries(labels)) {
        console.log(`批量模式 - 处理标签 ${labelKey}:`, selectedValue, '类型:', typeof selectedValue);
        
        if (selectedValue) {
          const values = Array.isArray(selectedValue) ? selectedValue : [selectedValue];
          values.forEach((value, index) => {
            console.log(`批量模式 - ${labelKey} 值${index}:`, value, '类型:', typeof value);
            
            if (typeof value === 'string' && value.trim()) {
              // 处理可能包含逗号分隔的复合标签值
              const splitValues = value.split(',').map(v => v.trim()).filter(v => v !== '');
              console.log(`批量模式 - ${labelKey} 分割后的值:`, splitValues);
              
              splitValues.forEach(splitValue => {
                businessLabelValues.add(splitValue);
                console.log(`批量模式 - 添加到业务标签集合: "${splitValue}"`);
              });
            }
          });
        }
      }
      
      console.log('批量模式 - 最终业务标签值集合:', Array.from(businessLabelValues));
      
      // 3. 匹配流程节点
      const matchedProcessNodes: any[] = [];
      console.log('批量模式 - 开始匹配流程节点，总节点数:', processNodes.length);
      
      for (const processNode of processNodes) {
        const processFields = processNode.fields;
        const nodeName = processFields[NODE_NAME_FIELD_ID];
        const processLabels = processFields[PROCESS_LABEL_FIELD_ID];
        const processOrder = processFields[PROCESS_ORDER_FIELD_ID];
        const weekendDays = processFields[WEEKEND_DAYS_FIELD_ID] || [];
        const excludedDates = processFields[EXCLUDED_DATES_FIELD_ID] || [];
        const startDateRule = processFields[START_DATE_RULE_FIELD_ID];
        const dateAdjustmentRule = processFields[DATE_ADJUSTMENT_RULE_FIELD_ID];
        
        // 处理节点名称
        let nodeNameText = '';
        if (typeof nodeName === 'string') {
          nodeNameText = nodeName;
        } else if (nodeName && nodeName.text) {
          nodeNameText = nodeName.text;
        }
        
        if (!nodeNameText) continue;
        
        // 处理流程标签数据，与生成模式保持一致
        const processLabelTexts: string[] = [];
        if (processLabels && Array.isArray(processLabels)) {
          for (const labelItem of processLabels) {
            const labelText = extractText(labelItem);
            if (labelText && labelText.trim()) {
              processLabelTexts.push(labelText.trim());
            }
          }
        }
        
        // 与生成模式保持一致：如果流程标签为空，跳过该节点
        if (processLabelTexts.length === 0) {
          console.log(`批量模式 - 流程节点 "${nodeNameText}" 标签为空，跳过`);
          continue;
        }
        
        console.log(`批量模式 - 检查流程节点 "${nodeNameText}":`, {
          流程标签: processLabelTexts,
          流程顺序: processOrder
        });
        
        // 处理流程标签匹配
        let isMatched = false;
        const matchedLabels: string[] = [];
        
        // 改为OR逻辑：只要有一个标签匹配就认为节点匹配
        for (const processLabelText of processLabelTexts) {
          console.log(`批量模式 - 检查流程标签: "${processLabelText}"`);
          
          // 对流程标签也进行分割处理，以支持复合标签值
          const processLabelValues = processLabelText.split(',').map(v => v.trim()).filter(v => v !== '');
          console.log(`批量模式 - 流程标签分割后: [${processLabelValues.join(', ')}]`);
          
          // 检查分割后的每个流程标签值是否在业务标签集合中
          for (const processLabelValue of processLabelValues) {
            if (businessLabelValues.has(processLabelValue)) {
              matchedLabels.push(processLabelValue);
              isMatched = true;
              console.log(`批量模式 - 流程节点 "${nodeNameText}" 匹配成功，匹配的标签: "${processLabelValue}"`);
              break; // 找到一个匹配就足够了
            } else {
              console.log(`批量模式 - 流程标签值 "${processLabelValue}" 未匹配`);
            }
          }
          
          if (isMatched) break; // 已经匹配，不需要继续检查其他标签
        }
        
        if (isMatched) {
          matchedProcessNodes.push({
            nodeName: nodeNameText,
            processOrder: typeof processOrder === 'number' ? processOrder : parseInt(processOrder) || 0,
            matchedLabels,
            weekendDays: Array.isArray(weekendDays) ? weekendDays : [],
            excludedDates: Array.isArray(excludedDates) ? excludedDates : [],
            startDateRule,
            dateAdjustmentRule
          });
          console.log(`批量模式 - 添加匹配的流程节点: "${nodeNameText}"`);
        } else {
          console.log(`批量模式 - 流程节点 "${nodeNameText}" 未匹配`);
        }
      }
      
      // 按流程顺序排序
      matchedProcessNodes.sort((a, b) => a.processOrder - b.processOrder);
      
      if (matchedProcessNodes.length === 0) {
        throw new Error('没有匹配的流程节点');
      }
      
      // 4. 获取时效数据并计算时间线
      const timelineTable = await bitable.base.getTable(TIMELINE_TABLE_ID);
      const timelineRecords = await timelineTable.getRecords({
        pageSize: 5000
      });
      
      // 获取时效表的标签字段映射（只需要获取一次）
      const timelineFieldMetaList = await timelineTable.getFieldMetaList();
      const timelineLabelFields: {[key: string]: string} = {};
      
      // 查找关系字段和计算方式字段
      let relationshipFieldId = '';
      let calculationMethodFieldId = '';
      
      for (const fieldMeta of timelineFieldMetaList) {
        const match = fieldMeta.name.match(/^标签([1-9]|10)$/);
        if (match) {
          const labelKey = `标签${match[1]}`;
          timelineLabelFields[labelKey] = fieldMeta.id;
        }
        // 查找关系字段
        if (fieldMeta.name === '关系' || fieldMeta.id === 'fldaIDAhab') {
          relationshipFieldId = fieldMeta.id;
        }
        // 查找时效计算方式字段
        if (fieldMeta.name === '时效计算方式' || fieldMeta.id === 'fldxfLZNUu') {
          calculationMethodFieldId = fieldMeta.id;
        }
      }
      
      // 构建时效数据索引
      const timelineIndexByNode = new Map<string, any[]>();
      
      for (const timelineRecord of timelineRecords.records || []) {
        const timelineFields = timelineRecord.fields;
        const timelineNodeName = timelineFields[TIMELINE_NODE_FIELD_ID];
        
        let timelineNodeNames: string[] = [];
        
        if (typeof timelineNodeName === 'string') {
          timelineNodeNames = timelineNodeName.split(',').map(name => name.trim());
        } else if (Array.isArray(timelineNodeName)) {
          timelineNodeNames = timelineNodeName.map(item => {
            if (typeof item === 'string') {
              return item.trim();
            } else if (item && item.text) {
              return item.text.trim();
            }
            return '';
          }).filter(name => name);
        } else if (timelineNodeName && timelineNodeName.text) {
          timelineNodeNames = timelineNodeName.text.split(',').map(name => name.trim());
        }
        
        for (const nodeName of timelineNodeNames) {
          const normalizedName = nodeName.toLowerCase();
          if (!timelineIndexByNode.has(normalizedName)) {
            timelineIndexByNode.set(normalizedName, []);
          }
          timelineIndexByNode.get(normalizedName)!.push({
            record: timelineRecord,
            fields: timelineFields
          });
        }
      }
      
      // 5. 计算每个节点的时效（遵循生成模式的匹配逻辑）
      const results: any[] = [];
      let cumulativeStartTime = startTime || new Date();
      
      for (const processNode of matchedProcessNodes) {
        console.log(`批量模式 - 开始处理流程节点: "${processNode.nodeName}"`);
        
        // 根据流程节点名称，在时效表中查找匹配的记录（与生成模式一致）
        const normalizedProcessName = processNode.nodeName.trim().toLowerCase();
        const candidateRecords = timelineIndexByNode.get(normalizedProcessName) || [];
        
        console.log(`批量模式 - 节点 "${processNode.nodeName}" 找到 ${candidateRecords.length} 个候选时效记录`);
        
        let timelineValue = null;
        let matchedTimelineRecord = null;
        
        // 收集所有匹配的候选记录（与生成模式保持一致）
        const matchedCandidates: any[] = [];
        
        // 在候选记录中进行标签匹配，收集所有匹配的记录
        for (const candidate of candidateRecords) {
          const { record: timelineRecord, fields: timelineFields } = candidate;
          
          // 进行完整的标签匹配逻辑（与生成模式保持一致）
          let isLabelsMatched = true;
          
          // 检查时效表中每个有值的标签是否都包含在业务标签中
          for (const [labelKey, timelineFieldId] of Object.entries(timelineLabelFields)) {
            const timelineLabelValue = timelineFields[timelineFieldId];
            
            // 处理时效表中的标签值
            let timelineLabelTexts: string[] = [];
            
            if (typeof timelineLabelValue === 'string' && timelineLabelValue.trim()) {
              timelineLabelTexts = [timelineLabelValue.trim()];
            } else if (timelineLabelValue && timelineLabelValue.text && timelineLabelValue.text.trim()) {
              timelineLabelTexts = [timelineLabelValue.text.trim()];
            } else if (Array.isArray(timelineLabelValue) && timelineLabelValue.length > 0) {
              // 多选字段，获取所有值
              timelineLabelTexts = timelineLabelValue.map(item => {
                if (typeof item === 'string') return item.trim();
                if (item && item.text) return item.text.trim();
                return '';
              }).filter(text => text);
            }
            
            // 如果时效表中该标签有值，则检查该标签的所有值是否都包含在业务标签中
            if (timelineLabelTexts.length > 0) {
              let allValuesMatched = true;
              
              for (const timelineText of timelineLabelTexts) {
                if (!businessLabelValues.has(timelineText)) {
                  allValuesMatched = false;
                  console.log(`批量模式 - 时效表标签 ${labelKey} 的值 "${timelineText}" 不在业务选择的标签中`);
                  break;
                }
              }
              
              if (!allValuesMatched) {
                console.log(`批量模式 - 时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 不完全包含在业务选择的标签中`);
                isLabelsMatched = false;
                break;
              } else {
                console.log(`批量模式 - 时效表标签 ${labelKey} 的值 [${timelineLabelTexts.join(', ')}] 完全匹配成功`);
              }
            }
            // 如果时效表中该标签为空，则跳过检查（空标签不影响匹配）
          }
          
          if (isLabelsMatched) {
            const timelineValueField = timelineFields[TIMELINE_FIELD_ID];
            const calculationMethodField = timelineFields[calculationMethodFieldId];
            const relationshipField = timelineFields[relationshipFieldId];
            
            if (timelineValueField !== null && timelineValueField !== undefined) {
              let candidateTimelineValue = 0;
              
              // 解析时效值（与生成模式保持一致）
              if (typeof timelineValueField === 'number') {
                candidateTimelineValue = timelineValueField;
              } else if (typeof timelineValueField === 'string') {
                const parsedValue = parseFloat(timelineValueField);
                candidateTimelineValue = isNaN(parsedValue) ? 0 : parsedValue;
              } else if (timelineValueField && typeof timelineValueField === 'object' && timelineValueField.value !== undefined) {
                candidateTimelineValue = timelineValueField.value;
              }
              
              // 获取计算方式
              let calculationMethod = '外部'; // 默认值
              if (calculationMethodField) {
                if (typeof calculationMethodField === 'string') {
                  calculationMethod = calculationMethodField;
                } else if (calculationMethodField && typeof calculationMethodField === 'object' && calculationMethodField.text) {
                  calculationMethod = calculationMethodField.text;
                }
              }
              
              // 获取关系类型
              let relationshipType = '默认';
              if (relationshipField) {
                if (typeof relationshipField === 'string') {
                  relationshipType = relationshipField;
                } else if (relationshipField && typeof relationshipField === 'object' && relationshipField.text) {
                  relationshipType = relationshipField.text;
                }
              }
              
              // 根据计算方式转换时效值（小时转天）
              let convertedTimelineValue = 0;
              if (calculationMethod === '内部') {
                convertedTimelineValue = Math.round((candidateTimelineValue / 9) * 1000) / 1000;
              } else {
                convertedTimelineValue = Math.round((candidateTimelineValue / 24) * 1000) / 1000;
              }
              
              // 添加到匹配候选列表
              matchedCandidates.push({
                record: timelineRecord,
                timelineValue: convertedTimelineValue,
                originalHours: candidateTimelineValue,
                calculationMethod: calculationMethod,
                relationshipType: relationshipType
              });
            }
          }
        }
        
        // 处理匹配的候选记录（与生成模式保持一致）
        let finalTimelineValue = 0;
        let processingRule = '默认';
        
        if (matchedCandidates.length > 0) {
          // 获取主要关系类型（用于决定处理方式）
          const relationshipTypes = matchedCandidates.map(c => c.relationshipType);
          const primaryRelationshipType = relationshipTypes.find(type => type === '累加值' || type === '最大值') || '默认';
          
          // 使用关系字段决定处理方式（累加值、最大值、默认）
          processingRule = primaryRelationshipType || '默认';
          
          console.log('批量模式 - processingRule:', processingRule);
          
          if (processingRule === '累加值') {
            finalTimelineValue = matchedCandidates.reduce((sum, candidate) => sum + candidate.timelineValue, 0);
            const totalOriginalHours = matchedCandidates.reduce((sum, candidate) => sum + candidate.originalHours, 0);
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 累加值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`累加结果: 总计${totalOriginalHours}小时 → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          } else if (processingRule === '最大值') {
            finalTimelineValue = Math.max(...matchedCandidates.map(c => c.timelineValue));
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 最大值处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`最大值结果: ${maxCandidate?.originalHours}小时(${maxCandidate?.calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = maxCandidate?.record || matchedCandidates[0].record;
          } else {
            finalTimelineValue = matchedCandidates[0].timelineValue;
            
            console.log(`批量模式 - 节点 ${processNode.nodeName} 默认处理 - 找到 ${matchedCandidates.length} 条匹配记录:`);
            matchedCandidates.forEach((candidate, index) => {
              console.log(`  记录${index + 1}: ID=${candidate.record.id || candidate.record.recordId}, 时效=${candidate.originalHours}小时(${candidate.timelineValue}天), 计算方式=${candidate.calculationMethod}`);
            });
            console.log(`默认结果: 使用第一条记录 ${matchedCandidates[0].originalHours}小时(${matchedCandidates[0].calculationMethod}) → ${finalTimelineValue}天`);
            
            matchedTimelineRecord = matchedCandidates[0].record;
          }
          
          timelineValue = finalTimelineValue;
        }
        
        // 计算节点时间（与生成模式保持一致）
        let nodeStartTime = new Date(cumulativeStartTime);
        let nodeEndTime = new Date(nodeStartTime);
        let nodeCalculationMethod = '外部'; // 默认计算方式
        
        // 如果有匹配的候选记录，使用其计算方式
        if (matchedCandidates.length > 0) {
          if (processingRule === '累加值') {
            nodeCalculationMethod = matchedCandidates[0].calculationMethod;
          } else if (processingRule === '最大值') {
            const maxCandidate = matchedCandidates.find(c => c.timelineValue === finalTimelineValue);
            nodeCalculationMethod = maxCandidate?.calculationMethod || matchedCandidates[0].calculationMethod;
          } else {
            nodeCalculationMethod = matchedCandidates[0].calculationMethod;
          }
        }
        
        if (timelineValue && timelineValue > 0) {
          // 根据计算方式调整开始时间
          const adjustedStartTime = adjustToNextWorkingHour(nodeStartTime, nodeCalculationMethod, processNode.weekendDays, processNode.excludedDates || []);
          
          let endDate: Date;
          if (nodeCalculationMethod === '内部') {
            // 使用内部工作时间计算
            endDate = addInternalBusinessTime(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          } else {
            // 使用原有的24小时制计算
            endDate = addBusinessDaysWithHolidays(adjustedStartTime, timelineValue, processNode.weekendDays, processNode.excludedDates || []);
          }
          
          nodeStartTime = adjustedStartTime;
          nodeEndTime = endDate;
        }
        
        results.push({
          processOrder: processNode.processOrder,
          nodeName: processNode.nodeName,
          matchedLabels: processNode.matchedLabels,
          timelineValue: timelineValue,
          estimatedStart: formatDate(nodeStartTime), // 使用默认格式，与生成模式一致
          estimatedEnd: formatDate(nodeEndTime), // 使用默认格式，与生成模式一致
          timelineRecordId: matchedTimelineRecord ? (matchedTimelineRecord.id || matchedTimelineRecord.recordId) : null,
          calculationMethod: nodeCalculationMethod, // 使用实际的计算方式
          weekendDaysConfig: processNode.weekendDays,
          skippedWeekends: 0,
          actualDays: calculateActualDays(formatDate(nodeStartTime), formatDate(nodeEndTime)), // 使用一致的格式
          startDateRule: processNode.startDateRule,
          dateAdjustmentRule: processNode.dateAdjustmentRule,
          // 新增：保存所有匹配记录的信息（用于累加情况）
          allMatchedRecords: matchedCandidates.length > 1 ? matchedCandidates.map(candidate => ({
            recordId: candidate.record.id || candidate.record.recordId || candidate.record._id || candidate.record.record_id,
            timelineValue: candidate.timelineValue,
            originalHours: candidate.originalHours,
            calculationMethod: candidate.calculationMethod,
            relationshipType: candidate.relationshipType
          })) : null,
          // 新增：标识是否为累加处理
          isAccumulated: processingRule === '累加值' && matchedCandidates.length > 1
        });
        
        // 更新累积时间
        if (timelineValue && timelineValue > 0) {
          cumulativeStartTime = new Date(nodeEndTime);
        }
      }
      
      console.log('批量计算结果:', results);
      
      // 6. 写入数据到货期记录表和流程数据表
      if (results.length > 0) {
        console.log('=== 批量模式：开始写入数据 ===');
        console.log('批量写入 - sourceRecordId:', sourceRecordId);
        console.log('批量写入 - labels:', labels);
        console.log('批量写入 - expectedDate:', expectedDate);
        console.log('批量写入 - style:', style);
        console.log('批量写入 - color:', color);
        console.log('批量写入 - foreignId:', foreignId);
        console.log('批量写入 - text2:', text2);
        console.log('批量写入 - startTime:', startTime);
        
        try {
          // 为标准写入函数准备数据：构造临时的数据结构
          console.log('批量写入 - 设置临时状态以适配标准写入函数');
          
          // 构造临时的recordDetails，包含当前记录的字段信息
          const tempRecordDetails = [{
            id: sourceRecordId,
            fields: {
              'fldpvBfeC0': foreignId, // 外键ID字段
              'fld6Uw95kt': style,     // 样式字段
              'flde85ni4O': color,     // 颜色字段
              'fldG6LZnmU': text2      // 文本字段2
            }
          }];
          
          // 构造批量数据对象（包含必要的业务字段）
          const batchDataForWriting = {
            selectedRecords: [sourceRecordId],
            recordDetails: tempRecordDetails,
            labels,           // 标签汇总（对象）
            expectedDate,     // 客户期望日期（Date）
            startTime         // 起始时间（Date）
          };
          
          console.log('批量写入 - 临时数据构造完成，开始调用标准写入函数');
          console.log('批量写入 - batchDataForWriting:', batchDataForWriting);
          
          // 写入流程数据表 - 使用标准函数，传递批量数据
          console.log('批量写入 - 调用标准writeToProcessDataTable函数');
          const processRecordIds = await writeToProcessDataTable(results, batchDataForWriting);
          console.log('批量写入 - 流程数据表写入完成，记录ID:', processRecordIds);
          
          // 写入货期记录表 - 使用标准函数，传递批量数据和空的调整信息
          console.log('批量写入 - 调用标准writeToDeliveryRecordTable函数');
          await writeToDeliveryRecordTable(results, processRecordIds, {}, batchDataForWriting);
          console.log('批量写入 - 货期记录表写入完成');
          
          // 批量写入成功后，设置全局状态以便快照保存
          console.log('批量写入 - 设置全局状态以便快照保存');
          setSelectedRecords([sourceRecordId]);
          setRecordDetails(tempRecordDetails);
          setSelectedLabels(labels);
          setCurrentStyleText(extractText(style));
          setCurrentColorText(extractText(color));
          setCurrentText2(extractText(text2));
          setCurrentForeignId(extractText(foreignId));
          setExpectedDate(expectedDate);
          setStartTime(startTime);
          
        } catch (error) {
          console.error('批量写入失败:', error);
          throw error;
        }
        
        console.log('=== 批量模式：数据写入完成 ===');
      }
      
    } catch (error) {
      console.error('批量时效计算失败:', error);
      throw error;
    }
  };



  // 执行定价数据查询
  const executeQuery = async (packId: string, packType: string) => {
    setQueryLoading(true);
    try {
      // 使用 apiService 中的函数
      const data = await executePricingQuery(packId, packType, selectedLabels);
      setQueryResults(data);
      
      // 处理品类属性填充到标签8的逻辑保持不变
      if (data && data.length > 0) {
        const label8Options = labelOptions['标签8'] || [];
        const matchingCategoryValues: string[] = [];
        
        data.forEach((record: any) => {
          if (record.品类属性 && record.品类属性.trim() !== '') {
            const categoryValue = record.品类属性.trim();
            const matchingOption = label8Options.find(option => 
              option.value === categoryValue || option.label === categoryValue
            );
            
            if (matchingOption && !matchingCategoryValues.includes(categoryValue)) {
              matchingCategoryValues.push(categoryValue);
            }
          }
        });
        
        if (matchingCategoryValues.length > 0) {
          setSelectedLabels(prev => ({
            ...prev,
            '标签8': matchingCategoryValues
          }));
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已将 ${matchingCategoryValues.length} 个品类属性填充到标签8: ${matchingCategoryValues.join(', ')}`
            });
          }
        }
      }
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '查询成功'
        });
      }
      
    } catch (error: any) {
      console.error('数据库查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `数据库查询失败: ${error.message}`
        });
      }
    } finally {
      setQueryLoading(false);
    }
  };

  // 执行二次工艺查询
  const executeSecondaryProcessQueryLocal = async (packId: string, packType: string) => {
    setSecondaryProcessLoading(true);
    try {
      const data = await executeSecondaryProcessQuery(packId, packType);
      setSecondaryProcessResults(data);
      
      // 处理二次工艺填充到标签7的逻辑
      if (data && data.length > 0) {
        const label7Options = labelOptions['标签7'] || [];
        const matchingProcessValues: string[] = [];
        
        data.forEach((record: any) => {
          if (record.costs_type && record.costs_type.trim() !== '') {
            const processValue = record.costs_type.trim();
            const matchingOption = label7Options.find(option => 
              option.value === processValue || option.label === processValue
            );
            
            if (matchingOption && !matchingProcessValues.includes(processValue)) {
              matchingProcessValues.push(processValue);
            }
          }
        });
        
        if (matchingProcessValues.length > 0) {
          setSelectedLabels(prev => ({
            ...prev,
            '标签7': matchingProcessValues
          }));
          
          if (bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已将 ${matchingProcessValues.length} 个二次工艺填充到标签7: ${matchingProcessValues.join(', ')}`
            });
          }
        }
      }
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '二次工艺查询成功'
        });
      }
    } catch (error: any) {
      console.error('二次工艺查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `二次工艺查询失败: ${error.message}`
        });
      }
    } finally {
      setSecondaryProcessLoading(false);
    }
  };

  // 执行定价详情查询
  const executePricingDetailsQueryLocal = async (packId: string) => {
    setPricingDetailsLoading(true);
    try {
      const data = await executePricingDetailsQuery(packId);
      setPricingDetailsResults(data);
      
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'success',
          message: '定价详情查询成功'
        });
      }
    } catch (error: any) {
      console.error('定价详情查询出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: `定价详情查询失败: ${error.message}`
        });
      }
    } finally {
      setPricingDetailsLoading(false);
    }
  };

  // 处理数据库查询
  const handleQueryDatabase = async (record: any) => {
    // 从记录字段中提取 packId 和 packType
    let packId = '';
    let packType = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    // 提取 pack_type (fldSAF9qXe)
    if (record.fields.fldSAF9qXe && record.fields.fldSAF9qXe.text) {
      packType = record.fields.fldSAF9qXe.text;
    }
    
    if (!packId || !packType) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id 或 pack_type)'
        });
      }
      return;
    }
    
    await executeQuery(packId, packType);
  };

  // 处理二次工艺查询
  const handleSecondaryProcessQuery = async (record: any) => {
    // 从记录字段中提取 packId 和 packType
    let packId = '';
    let packType = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    // 提取 pack_type (fldSAF9qXe)
    if (record.fields.fldSAF9qXe && record.fields.fldSAF9qXe.text) {
      packType = record.fields.fldSAF9qXe.text;
    }
    
    if (!packId || !packType) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id 或 pack_type)'
        });
      }
      return;
    }
    
    await executeSecondaryProcessQueryLocal(packId, packType);
  };

  // 处理定价详情查询
  const handlePricingDetailsQuery = async (record: any) => {
    // 从记录字段中提取 packId
    let packId = '';
    
    // 提取 pack_id (fldpvBfeC0)
    if (record.fields.fldpvBfeC0 && Array.isArray(record.fields.fldpvBfeC0) && record.fields.fldpvBfeC0.length > 0) {
      packId = record.fields.fldpvBfeC0[0].text;
    }
    
    if (!packId) {
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '缺少必要的查询参数 (pack_id)'
        });
      }
      return;
    }
    
    await executePricingDetailsQueryLocal(packId);
  };



  // 获取记录详情的函数
  const fetchRecordDetails = async (recordIdList: string[]) => {

    try {
      const table = await bitable.base.getTable(TABLE_ID);
      
      // 并行获取所有记录详情
      const recordPromises = recordIdList.map(recordId => 
        table.getRecordById(recordId)
      );
      
      const records = await Promise.all(recordPromises);
      
      const recordValList = records.map((record, index) => {
        console.log(`记录 ${recordIdList[index]} 的详情:`, record);
        console.log(`记录 ${recordIdList[index]} 的fldpvBfeC0字段:`, record.fields['fldpvBfeC0']);
        return {
          id: recordIdList[index],
          fields: record.fields
        };
      });
      
      setRecordDetails(recordValList);
    } catch (error) {
      console.error('获取记录详情失败:', error);
    }
  };

  // 选择记录
  const handleSelectRecords = async () => {
    // 切换版单数据时重置全局变量，清空旧结果与回填状态
    resetGlobalState();
    setLoading(true);
    // 清空标签选择
    setSelectedLabels({});
    setExpectedDate(null);
    
    try {
      // 修改这里：使用正确的 API
      const recordIdList = await bitable.ui.selectRecordIdList(TABLE_ID, VIEW_ID);
      
      setSelectedRecords(recordIdList);
      
      // 获取记录的详细信息
      if (recordIdList.length > 0) {
        // 并行获取记录详情和字段元数据
        const table = await bitable.base.getTable(TABLE_ID);
        const [recordPromises, fieldMetaList] = await Promise.all([
          Promise.all(recordIdList.map(recordId => table.getRecordById(recordId))),
          table.getFieldMetaList()
        ]);
        
        const recordValList = recordPromises.map((record, index) => ({
          id: recordIdList[index],
          fields: record.fields
        }));
        
        if (recordValList.length > 0) {
          const firstRecord = recordValList[0];
          const extractedLabels: {[key: string]: string} = {};
          
          // 建立字段名到字段ID的映射
          const fieldNameToId: {[key: string]: string} = {};
          for (const fieldMeta of fieldMetaList) {
            fieldNameToId[fieldMeta.name] = fieldMeta.id;
          }
          
          // 提取标签值的辅助函数
          const extractFieldValue = (fieldName: string) => {
            const fieldId = fieldNameToId[fieldName];
            if (fieldId && firstRecord.fields[fieldId]) {
              const fieldValue = firstRecord.fields[fieldId];
              
              // 优先处理数组格式（公式字段）
              if (Array.isArray(fieldValue) && fieldValue.length > 0) {
                const firstItem = fieldValue[0];
                if (typeof firstItem === 'string') {
                  return firstItem;
                } else if (firstItem && (firstItem.text || firstItem.name)) {
                  return firstItem.text || firstItem.name;
                }
              }
              // 处理对象格式（普通字段）
              else if (typeof fieldValue === 'object' && fieldValue !== null) {
                if (fieldValue.text) {
                  return fieldValue.text;
                } else if (fieldValue.name) {
                  return fieldValue.name;
                }
              }
              // 处理字符串格式
              else if (typeof fieldValue === 'string') {
                return fieldValue.trim();
              }
            }
            return '';
          };
          
          // 直接通过字段ID提取fld6Uw95kt的值
          const getFieldValueById = (fieldId: string) => {
            if (fieldId && firstRecord.fields[fieldId]) {
              const fieldValue = firstRecord.fields[fieldId];
              
              // 优先处理数组格式（公式字段）
              if (Array.isArray(fieldValue) && fieldValue.length > 0) {
                const firstItem = fieldValue[0];
                if (typeof firstItem === 'string') {
                  return firstItem;
                } else if (firstItem && (firstItem.text || firstItem.name)) {
                  return firstItem.text || firstItem.name;
                }
              }
              // 处理对象格式（普通字段）
              else if (typeof fieldValue === 'object' && fieldValue !== null) {
                if (fieldValue.text) {
                  return fieldValue.text;
                } else if (fieldValue.name) {
                  return fieldValue.name;
                }
              }
              // 处理字符串格式
              else if (typeof fieldValue === 'string') {
                return fieldValue.trim();
              }
            }
            return '';
          };
          
          // 提取fld6Uw95kt字段的值
          const mainRecordDisplayValue = getFieldValueById('fld6Uw95kt') || firstRecord.id;
          
          // 将这个值存储到recordDetails中，以便在UI中使用
          const updatedRecordValList = recordValList.map((record, index) => ({
            ...record,
            displayValue: index === 0 ? mainRecordDisplayValue : record.id
          }));
          
          setRecordDetails(updatedRecordValList);
          
          // 提取各个标签的值
          const label2Value = extractFieldValue('品类名称');
          const label3Value = extractFieldValue('大类名称');
          const label4Value = extractFieldValue('中类名称');
          const label5Value = extractFieldValue('小类名称');
          const label6Value = extractFieldValue('工艺难易度');
          
          // 设置提取到的标签值
          const newSelectedLabels: {[key: string]: string | string[]} = {};
          if (label2Value) newSelectedLabels['标签2'] = label2Value;
          if (label3Value) newSelectedLabels['标签3'] = label3Value;
          if (label4Value) newSelectedLabels['标签4'] = label4Value;
          if (label5Value) newSelectedLabels['标签5'] = label5Value;
          if (label6Value) newSelectedLabels['标签6'] = label6Value;
          
          // 添加标签10的自动填充
          newSelectedLabels['标签10'] = ['复版', '开货版不打版'];
          
          // 保留用户手动选择的标签1、7、8、9
          setSelectedLabels(prev => ({
            ...prev,
            ...newSelectedLabels
          }));
          
          console.log('自动提取的标签值:', newSelectedLabels);
          
          // 显示提取结果的提示
          if (Object.keys(newSelectedLabels).length > 0 && bitable.ui.showToast) {
            await bitable.ui.showToast({
              toastType: 'success',
              message: `已自动提取 ${Object.keys(newSelectedLabels).length} 个标签值`
            });
          }
          
          // 自动执行所有三个查询 - 对第一条记录顺序执行查询
          // 顺序执行查询，避免 loading 状态冲突
          try {
            await handleQueryDatabase(recordValList[0]);
            await handleSecondaryProcessQuery(recordValList[0]);
            await handlePricingDetailsQuery(recordValList[0]);
          } catch (queryError) {
            console.error('自动查询出错:', queryError);
          }
        }
      } else {
        setRecordDetails([]);
      }
    } catch (error) {
      console.error('选择记录时出错:', error);
      if (bitable.ui.showToast) {
        await bitable.ui.showToast({
          toastType: 'error',
          message: '选择记录时出错，请重试'
        });
      }
    } finally {
      setLoading(false);
    }
  };

  // 清空选中的记录
  const handleClearRecords = () => {
    setSelectedRecords([]);
    setRecordDetails([]);
    setQueryResults([]);
    setSecondaryProcessResults([]);
    setPricingDetailsResults([]);
    // 同时清空标签选择
    setSelectedLabels({});
    setExpectedDate(null);
  };

  // 定价数据表格列定义
  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
      key: 'id',
    },
    {
      title: 'Pack ID',
      dataIndex: 'pack_id',
      key: 'pack_id',
    },
    {
      title: 'Pack Type',
      dataIndex: 'pack_type',
      key: 'pack_type',
    },
    {
      title: '物料编码',
      dataIndex: 'material_code',
      key: 'material_code',
    },
    {
      title: '一级分类',
      dataIndex: 'category1_name',
      key: 'category1_name',
    },
    {
      title: '二级分类',
      dataIndex: 'category2_name',
      key: 'category2_name',
    },
    {
      title: '三级分类',
      dataIndex: 'category3_name',
      key: 'category3_name',
    },
    {
      title: '品类属性',
      dataIndex: '品类属性',
      key: '品类属性',
    },
  ];

  // 二次工艺表格列定义
  const secondaryProcessColumns = [
    {
      title: 'ID',
      dataIndex: 'id',
      key: 'id',
    },
    {
      title: 'Foreign ID',
      dataIndex: 'foreign_id',
      key: 'foreign_id',
    },
    {
      title: 'Pack Type',
      dataIndex: 'pack_type',
      key: 'pack_type',
    },
    {
      title: '项目',
      dataIndex: 'costs_item',
      key: 'costs_item',
    },
    {
      title: '二次工艺',
      dataIndex: 'costs_type',
      key: 'costs_type',
    },
    {
      title: '备注',
      dataIndex: 'remarks',
      key: 'remarks',
    },
  ];

  // 定价详情表格列定义
  const pricingDetailsColumns = [
    {
      title: 'Pack ID',
      dataIndex: 'pack_id',
      key: 'pack_id',
    },
    {
      title: '倍率',
      dataIndex: '倍率',
      key: '倍率',
    },
    {
      title: '加工费',
      dataIndex: '加工费',
      key: '加工费',
    },
    {
      title: '总价',
      dataIndex: '总价',
      key: '总价',
    },
  ];

  return (
    <div style={{ padding: '20px' }}>
      {/* 入口选择弹窗 */}
      <Modal
        title="请选择功能入口"
        visible={modeSelectionVisible}
        footer={null}
        onCancel={() => setModeSelectionVisible(false)}
        maskClosable={false}
      >
        <div style={{ display: 'flex', gap: 24, justifyContent: 'center', padding: '12px 8px 8px', flexWrap: 'wrap' }}>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('generate')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>生成流程日期</Title>
            <Text type='tertiary'>基于业务数据计算并生成节点时间线</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('generate')}>进入</Button>
            </div>
          </Card>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('adjust')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>调整流程日期</Title>
            <Text type='tertiary'>读取货期记录，精确还原时间线</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('adjust')}>进入</Button>
            </div>
          </Card>
          <Card 
            style={{ 
              width: 280, 
              cursor: 'pointer', 
              borderRadius: 12,
              boxShadow: '0 8px 24px rgba(0,0,0,0.06)',
              border: '1px solid #e5e7eb',
              background: 'linear-gradient(180deg, #fff, #f9fbff)'
            }} 
            onClick={() => chooseMode('batch')}
          >
            <Title heading={3} style={{ marginBottom: 8 }}>批量生成</Title>
            <Text type='tertiary'>批量生成多条流程记录</Text>
            <div style={{ marginTop: 16 }}>
              <Button type='primary' theme='solid' size='large' style={{ width: '100%' }} onClick={() => chooseMode('batch')}>进入</Button>
            </div>
          </Card>
        </div>
      </Modal>

      {mode === 'generate' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #3b82f6, #1d4ed8)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            数据查询工具
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>基于业务数据计算并生成节点时间线</Text>
        </div>
      )}
      {mode === 'batch' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #10b981, #059669)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            批量生成工具
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>批量生成多条流程记录，提高工作效率</Text>
        </div>
      )}
      {mode === 'adjust' && (
        <div style={{ marginBottom: '24px' }}>
          <Title heading={2} style={{ 
            background: 'linear-gradient(135deg, #f59e0b, #d97706)', 
            WebkitBackgroundClip: 'text', 
            WebkitTextFillColor: 'transparent',
            marginBottom: '8px'
          }}>
            调整流程日期
          </Title>
          <Text type="tertiary" style={{ fontSize: '14px' }}>读取货期记录，精确还原时间线</Text>
        </div>
      )}
      {/* 功能入口切换与调整入口 */}
      {mode !== null && (
        <div style={{ margin: '18px 0 14px' }}>
          <Space spacing={16} align='center'>
            <Select value={mode} onChange={(v) => setMode(v as any)}
              optionList={[
                { value: 'generate', label: '生成流程日期' }, 
                { value: 'adjust', label: '调整流程日期' },
                { value: 'batch', label: '批量生成' }
              ]} />
            {mode === 'adjust' && (
              <Space spacing={12} align='center'>
                <Button type="primary" onClick={async () => {
                  try {
                    const selection = await bitable.base.getSelection();
                    const recordId = selection?.recordId || '';
                    const tableId = selection?.tableId || '';
                    if (!recordId) {
                      if (bitable.ui.showToast) {
                        await bitable.ui.showToast({ toastType: 'warning', message: '请先在数据表中选中一条货期记录' });
                      }
                      return;
                    }
                    if (tableId && tableId !== DELIVERY_RECORD_TABLE_ID) {
                      if (bitable.ui.showToast) {
                        await bitable.ui.showToast({ toastType: 'warning', message: '请在货期记录表中选择记录' });
                      }
                      return;
                    }
                    setSelectedDeliveryRecordId(recordId);
                    await loadProcessDataFromDeliveryRecord(recordId);
                  } catch (e) {
                    console.error('读取当前选中记录失败:', e);
                    if (bitable.ui.showToast) {
                      await bitable.ui.showToast({ toastType: 'error', message: '读取当前选中记录失败' });
                    }
                  }
                }}>读取当前选中记录并还原流程数据</Button>
              </Space>
            )}
            {/* 批量处理功能 - 只在批量模式下显示 */}
          </Space>
        </div>
      )}
      
      {/* 时效计算结果模态框 */}
      <Modal
        title="预计开始和完成时间"
        visible={timelineVisible}
        onCancel={() => {
          setTimelineVisible(false);
          setTimelineAdjustments({}); // 关闭时重置调整
          setDeliveryMarginDeductions(0); // 关闭时重置交期余量扣减
          setCompletionDateAdjustment(0); // 关闭时重置最后流程完成日期调整
        }}
        footer={
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <Space align="center">
              <Text>缓冲期(天)：</Text>
              <InputNumber
                min={0}
                step={1}
                value={baseBufferDays}
                onChange={(val) => {
                  const n = Number(val);
                  setBaseBufferDays(Number.isFinite(n) && n >= 0 ? n : 0);
                }}
                style={{ width: 90 }}
              />
              <Button onClick={resetTimelineAdjustments}>
                重置所有调整
              </Button>
            </Space>
            <Button 
              type="primary" 
              onClick={async () => {
                try {
                  // 如果有当前批量记录信息，使用批量数据进行保存
                  if (currentBatchRecord) {
                    console.log('使用批量记录数据进行保存:', currentBatchRecord);
                    await saveTimelineData({
                      timelineResults: timelineResults,
                      selectedRecords: currentBatchRecord.selectedRecords,
                      recordDetails: currentBatchRecord.recordDetails,
                      timelineAdjustments: timelineAdjustments,
                      labels: currentBatchRecord.labels,
                      expectedDate: currentBatchRecord.expectedDate,
                      startTime: currentBatchRecord.startTime
                    });
                  } else {
                    // 普通模式保存
                    await saveTimelineData();
                  }
                } catch (error) {
                  // 错误已在saveTimelineData中处理
                }
                setTimelineVisible(false);
                // 清除批量记录信息
                setCurrentBatchRecord(null);
              }}
            >
              确定并保存
            </Button>
          </div>
        }
        width={900}
      >
        <div style={{ maxHeight: '80vh', overflowY: 'auto' }}>
          {timelineResults.length === 0 ? (
            <div style={{ textAlign: 'center', padding: '40px' }}>
              <Text type="tertiary">未找到匹配的时效数据</Text>
            </div>
          ) : (
            <div>
              <div style={{ marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '12px' }}>
                <Text strong>起始时间</Text>
                <DatePicker
                  style={{ width: 280 }}
                  placeholder="请选择起始时间"
                  value={startTime}
                  onChange={(date) => {
                    setStartTime(date);
                  }}
                  type="dateTime"
                  format="yyyy-MM-dd HH:mm"
                />
              </div>
              {timelineResults.map((result, index) => {
                const adjustment = timelineAdjustments[index] || 0;
                const baseValue = (typeof result.timelineValue === 'number')
                  ? result.timelineValue
                  : (typeof result.adjustedTimelineValue === 'number')
                    ? result.adjustedTimelineValue
                    : 0;
                const adjustedValue = baseValue + adjustment;
                
                // 检查是否为周转周期节点
                const isTurnoverNode = result.nodeName === '周转周期';
                
                // 检查是否存在周转周期为零的情况
                const hasTurnoverNodeWithZero = timelineResults.some((r, i) => {
                  if (r.nodeName === '周转周期') {
                    const adj = timelineAdjustments[i] || 0;
                    const baseVal = (typeof r.timelineValue === 'number')
                      ? r.timelineValue
                      : (typeof r.adjustedTimelineValue === 'number')
                        ? r.adjustedTimelineValue
                        : 0;
                    return (baseVal + adj) === 0;
                  }
                  return false;
                });
                
                // 当前节点是否为零值的周转周期节点
                const isCurrentTurnoverZero = isTurnoverNode && adjustedValue === 0;
                
                // 计算动态缓冲期，用于限制节点增加操作
                const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                
                // 新的复合限制逻辑：
                // 1. 如果缓冲期 > 0，允许操作
                // 2. 如果缓冲期 = 0，进一步判断交期余量
                // 3. 如果缓冲期 = 0 且交期余量 <= 0，禁止操作
                let hasNegativeBuffer = false;
                
                // 计算交期余量（仅用于显示，不用于限制）
                let deliveryMargin = 0;
                if (timelineResults.length > 0) {
                  // 获取有效的最后流程完成日期（与交期余量计算逻辑保持一致）
                  let effectiveLastProcess = null;
                  let lastCompletionDate = null;
                  
                  for (let i = timelineResults.length - 1; i >= 0; i--) {
                    const process = timelineResults[i];
                    const processDate = new Date(process.estimatedEnd);
                    
                    if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                      effectiveLastProcess = process;
                      lastCompletionDate = processDate;
                      break;
                    }
                  }
                  
                  if (!effectiveLastProcess) {
                    effectiveLastProcess = timelineResults[timelineResults.length - 1];
                    lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                  }
                  
                  // 计算最后完成日期（考虑调整）+ 动态缓冲期
                  const adjustedCompletionDate = new Date(lastCompletionDate);
                  adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                  
                  const deliveryDate = new Date(adjustedCompletionDate);
                  deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
                  
                  if (expectedDate) {
                    // 有客户期望日期：交期余量 = 客户期望日期 - (最后流程完成 + 缓冲期)
                    const timeDiff = expectedDate.getTime() - deliveryDate.getTime();
                    const baseDeliveryMargin = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                    deliveryMargin = baseDeliveryMargin - deliveryMarginDeductions;
                  } else {
                    // 无客户期望日期：交期余量 = (最后流程完成 + 缓冲期) - 今天
                    const today = new Date();
                    today.setHours(0, 0, 0, 0);
                    const timeDiff = deliveryDate.getTime() - today.getTime();
                    const baseDeliveryMargin = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                    deliveryMargin = baseDeliveryMargin - deliveryMarginDeductions;
                  }
                }
                
                // 执行复合限制判断 - 只有在缓冲期为0时才检查最终限制
                let canIncrease = false;
                if (dynamicBufferDays > 0) {
                  // 1. 缓冲期 > 0，允许操作
                  canIncrease = true;
                } else {
                  // 2. 缓冲期 = 0，检查最终限制：最后节点预计完成时间是否已达到客户期望日期
                  if (expectedDate && timelineResults.length > 0) {
                    // 获取有效的最后流程完成日期
                    let effectiveLastProcess = null;
                    let lastCompletionDate = null;
                    
                    for (let i = timelineResults.length - 1; i >= 0; i--) {
                      const process = timelineResults[i];
                      const processDate = new Date(process.estimatedEnd);
                      
                      if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                        effectiveLastProcess = process;
                        lastCompletionDate = processDate;
                        break;
                      }
                    }
                    
                    if (!effectiveLastProcess) {
                      effectiveLastProcess = timelineResults[timelineResults.length - 1];
                      lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                    }
                    
                    // 计算最后流程完成日期（包含调整）
                    const adjustedCompletionDate = new Date(lastCompletionDate);
                    adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                    
                    // 检查是否已达到客户期望日期
                    const timeDiffToExpected = expectedDate.getTime() - adjustedCompletionDate.getTime();
                    const daysToExpected = Math.ceil(timeDiffToExpected / (1000 * 60 * 60 * 24));
                    canIncrease = daysToExpected > 0; // 只有当还有剩余天数时才允许调整
                  } else {
                    // 无客户期望日期时，理论上可以无限调整
                    canIncrease = true;
                  }
                }
                hasNegativeBuffer = !canIncrease;
                
                return (
                  <Card key={index} style={{ marginBottom: '8px', padding: '12px', position: 'relative' }}>
                    <div style={{ position: 'absolute', top: '12px', left: '12px', zIndex: 1, display: 'flex', alignItems: 'center', gap: '16px' }}>
  <Title heading={6} style={{ margin: 0, color: '#1890ff', fontSize: '18px' }}>
    {result.processOrder && `${result.processOrder}. `}{result.nodeName}
    {result.isAccumulated && result.allMatchedRecords ? (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#000000', 
        fontWeight: 'normal' 
      }}>
        (累加 {result.allMatchedRecords.length} 条记录: {result.allMatchedRecords.map(record => record.recordId).join(', ')})
      </span>
    ) : result.timelineRecordId ? (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#000000', 
        fontWeight: 'normal' 
      }}>
        ({result.timelineRecordId})
      </span>
    ) : (
      <span style={{ 
        marginLeft: '8px', 
        fontSize: '12px', 
        color: '#ff4d4f', 
        fontWeight: 'normal' 
      }}>
        (无匹配记录)
      </span>
    )}
  </Title>
  
  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
    <Text style={{ fontSize: '14px', color: '#666', whiteSpace: 'nowrap' }}>实际完成：</Text>
    <DatePicker
      size="small"
      placeholder="选择日期"
      value={actualCompletionDates[index] || null}
      onChange={(date) => {
        setActualCompletionDates(prev => ({
          ...prev,
          [index]: date
        }));
        
        // 自动设置调整量：按工作日规则（考虑内部/外部、休息日、跳过日期）
        try {
          const currentResult = timelineResults[index];
          const startStr = currentResult?.estimatedStart;
          if (startStr && date) {
            const startDate = new Date(startStr);
            if (!isNaN(startDate.getTime())) {
              const calcRaw = currentResult?.calculationMethod || '外部';
              const calcMethod = (calcRaw === '内部' || calcRaw === 'internal') ? '内部' : '外部';
              const weekendDays = currentResult?.weekendDaysConfig || currentResult?.weekendDays || [];
              const excludedDates = Array.isArray(currentResult?.excludedDates) ? currentResult!.excludedDates : [];

              // 与正向计算一致：先对起始时间应用工作时间调整
              const adjustedStart = adjustToNextWorkingHour(startDate, calcMethod, weekendDays, excludedDates);
              const targetDate = new Date(date);

              // 使用二分搜索反推工作日数（按0.5天粒度），使得正向计算的结束时间尽量贴近目标日期
              const dayMs = 1000 * 60 * 60 * 24;
              const approxNatural = Math.max(0, (targetDate.getTime() - adjustedStart.getTime()) / dayMs);
              const endFor = (bd: number): Date => {
                if (bd <= 0) return new Date(adjustedStart);
                return calcMethod === '内部'
                  ? addInternalBusinessTime(new Date(adjustedStart), bd, weekendDays, excludedDates)
                  : addBusinessDaysWithHolidays(new Date(adjustedStart), bd, weekendDays, excludedDates);
              };

              let lo = 0;
              let hi = Math.max(1, approxNatural + 50);
              for (let it = 0; it < 40; it++) {
                const mid = (lo + hi) / 2;
                const end = endFor(mid);
                if (end.getTime() < targetDate.getTime()) {
                  lo = mid;
                } else {
                  hi = mid;
                }
              }
              const desiredBusinessDays = Math.round(hi * 2) / 2; // 与UI保持0.5粒度一致

              // 目标调整量 = 目标工作日数 - 基准时效值
              const baseValue = (typeof currentResult.timelineValue === 'number')
                ? currentResult.timelineValue
                : (typeof currentResult.adjustedTimelineValue === 'number')
                  ? currentResult.adjustedTimelineValue
                  : 0;

              const desiredAdjustmentAbs = desiredBusinessDays - baseValue;
              const currentAdj = timelineAdjustments[index] || 0;
              const deltaToApply = desiredAdjustmentAbs - currentAdj;
              if (deltaToApply !== 0) {
                const updated = handleTimelineAdjustment(index, deltaToApply);
                if (!updated) {
                  // 如果该节点不允许调整，仍然重算以联动后续节点
                  setTimeout(() => {
                    recalculateTimeline(timelineAdjustments, false);
                  }, 0);
                  return;
                }
              }
            }
          }
        } catch (e) {
          console.warn('自动调整量计算失败:', e);
        }

        // 无论如何都重新计算时间线以联动交期余量
        setTimeout(() => {
          recalculateTimeline(timelineAdjustments, false);
        }, 0);
      }}
      style={{ width: '140px' }}
      format="yyyy-MM-dd"
    />
  </div>
</div>
                    
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr 1fr', gap: '12px', marginTop: '40px' }}>
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>时效值调整：</Text>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, -0.5)}
                        disabled={adjustedValue <= 0 || isCurrentTurnoverZero}
                        style={{ minWidth: '28px', height: '24px', fontSize: '13px' }}
                        title={isCurrentTurnoverZero ? '周转周期为零，无法调整' : ''}
                      >
                        -0.5
                      </Button>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, -1)}
                        disabled={adjustedValue <= 0 || isCurrentTurnoverZero}
                        style={{ minWidth: '24px', height: '24px', fontSize: '13px' }}
                        title={isCurrentTurnoverZero ? '周转周期为零，无法调整' : ''}
                      >
                        -1
                      </Button>
                      <div style={{ 
                        minWidth: '70px', 
                        textAlign: 'center',
                        padding: '2px 6px',
                        border: '1px solid #d9d9d9',
                        borderRadius: '4px',
                        backgroundColor: adjustment !== 0 ? '#fff7e6' : '#f5f5f5',
                        fontSize: '13px'
                      }}>
                        <Text style={{ 
                          color: adjustedValue > 0 ? '#52c41a' : '#ff4d4f',
                          fontWeight: 'bold',
                          fontSize: '13px'
                        }}>
                          {adjustedValue.toFixed(1)} 工作日
                        </Text>
                        {adjustment !== 0 && (
                          <div style={{ fontSize: '10px', color: '#666', lineHeight: '1.2' }}>
                            原值: {baseValue.toFixed(1)}
                            <br />
                            调整: {adjustment > 0 ? '+' : ''}{adjustment.toFixed(1)}
                          </div>
                        )}
                      </div>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, 1)}
                        disabled={isCurrentTurnoverZero || (hasTurnoverNodeWithZero && !isTurnoverNode) || (isTurnoverNode && !isCurrentTurnoverZero) || hasNegativeBuffer}
                        style={{ minWidth: '24px', height: '24px', fontSize: '13px' }}
                        title={
                          isCurrentTurnoverZero ? '周转周期为零，无法调整' : 
                          (hasTurnoverNodeWithZero && !isTurnoverNode) ? '周转周期为零，其他节点无法增加' : 
                          (isTurnoverNode && !isCurrentTurnoverZero) ? '周转周期节点会自动调整，无法手动修改' : 
                          hasNegativeBuffer ? `缓冲期已耗尽且交期余量不足，不允许增加时效` : ''
                        }
                      >
                        +1
                      </Button>
                      <Button 
                        size="small" 
                        onClick={() => handleComplexAdjustment(index, 0.5)}
                        disabled={isCurrentTurnoverZero || (hasTurnoverNodeWithZero && !isTurnoverNode) || (isTurnoverNode && !isCurrentTurnoverZero) || hasNegativeBuffer}
                        style={{ minWidth: '28px', height: '24px', fontSize: '13px' }}
                        title={
                          isCurrentTurnoverZero ? '周转周期为零，无法调整' : 
                          (hasTurnoverNodeWithZero && !isTurnoverNode) ? '周转周期为零，其他节点无法增加' : 
                          (isTurnoverNode && !isCurrentTurnoverZero) ? '周转周期节点会自动调整，无法手动修改' : 
                          hasNegativeBuffer ? `缓冲期已耗尽且交期余量不足，不允许增加时效` : ''
                        }
                      >
                        +0.5
                      </Button>
                    </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>预计开始：</Text>
                        <Text style={{ fontSize: '14px' }}>{formatDate(result.estimatedStart)}</Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
          <Text>{getDayOfWeek(result.estimatedStart)}</Text>
        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>预计完成：</Text>
                        <Text style={{ 
                          color: result.estimatedEnd.includes('未找到') || result.estimatedEnd.includes('时效值为0') ? '#ff4d4f' : '#52c41a',
                          fontSize: '14px'
                        }}>
                          {result.estimatedEnd === '时效值为0' ? result.estimatedEnd : formatDate(result.estimatedEnd)}
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
          <Text>{getDayOfWeek(result.estimatedEnd)}</Text>
        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>实际跨度：</Text>
                        <Text style={{ color: '#1890ff', fontSize: '14px' }}>
                          {calculateActualDays(result.estimatedStart, result.estimatedEnd)} 自然日
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '1px' }}>
                          <Text>含 {adjustedValue.toFixed(1)} 工作日</Text>
                        </div>
                      </div>
                      
                      <div>
                        <Text strong style={{ display: 'block', marginBottom: '2px', fontSize: '15px' }}>计算方式：</Text>
                        <Text style={{ 
                          color: result.calculationMethod === '内部' ? '#1890ff' : '#52c41a',
                          fontSize: '14px'
                        }}>
                          {result.calculationMethod || '外部'}
                          {result.ruleDescription && (
                            <span style={{ 
                              marginLeft: '8px', 
                              color: '#ff7a00',
                              fontSize: '12px',
                              fontStyle: 'italic'
                            }}>
                              ({result.ruleDescription})
                            </span>
                          )}
                          <span 
                            style={{ 
                              marginLeft: '4px', 
                              cursor: 'help',
                              color: '#666',
                              fontSize: '12px',
                              display: 'inline-flex',
                              alignItems: 'center',
                              justifyContent: 'center',
                              width: '14px',
                              height: '14px',
                              borderRadius: '50%',
                              backgroundColor: '#f0f0f0',
                              border: '1px solid #d9d9d9'
                            }}
                            title={`计算方式详情：\n${result.calculationMethod === '内部' ? '内部计算 (9小时工作制)' : '外部计算 (24小时制)'}${result.ruleDescription ? `\n应用规则：${result.ruleDescription}` : ''}\n已跳过周末：${result.skippedWeekends || 0} 天\n${result.weekendDaysConfig && result.weekendDaysConfig.length > 0 ? `休息日配置：${result.weekendDaysConfig.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(', ')}` : '休息日配置：无固定休息日'}${result.calculationMethod === '内部' ? '\n工作时间：9:00-18:00 (9小时制)' : ''}${(Array.isArray(result.actualExcludedDates) && result.actualExcludedDates.length > 0) ? `\n\n跳过的具体日期：\n${result.actualExcludedDates.join('\n')}` : ''}`}
                          >
                            ?
                          </span>
                        </Text>
                        <div style={{ fontSize: '12px', color: '#666', marginTop: '2px' }}>
                          <Text>跳过日期：{(result.actualExcludedDatesCount && result.actualExcludedDatesCount > 0) ? `${result.actualExcludedDatesCount} 天` : '无'}</Text>
                        </div>
                      </div>
                    </div>
                  </Card>
                );
              })}
              
              {/* 计算公式展示卡片 */}
              {timelineResults.length > 0 && (
                <Card style={{ 
                  marginBottom: '16px', 
                  padding: '16px', 
                  background: 'linear-gradient(135deg, #e6f7ff 0%, #f0f9ff 100%)',
                  border: '2px solid #1890ff',
                  borderRadius: '12px',
                  boxShadow: '0 4px 12px rgba(24, 144, 255, 0.15)'
                }}>
                  <div style={{ textAlign: 'center' }}>
                    <Title heading={5} style={{ 
                      margin: '0 0 16px 0', 
                      color: '#1890ff',
                      fontSize: '20px',
                      fontWeight: 'bold'
                    }}>
                      📅 交期余量计算
                    </Title>
                    
                    <div style={{ 
                      display: 'grid', 
                      gridTemplateColumns: expectedDate ? '1fr auto 1fr auto 1fr auto 1fr auto 1fr' : '1fr auto 1fr auto 1fr auto 1fr', 
                      alignItems: 'center', 
                      gap: '12px',
                      marginBottom: '16px',
                      padding: '16px',
                      backgroundColor: 'rgba(255, 255, 255, 0.8)',
                      borderRadius: '8px',
                      border: '1px solid rgba(24, 144, 255, 0.2)'
                    }}>
                      {(() => {
                        // 获取有效的最后流程完成日期
                        let effectiveLastProcess = null;
                        let lastCompletionDate = null;
                        
                        // 从后往前查找第一个有效的流程完成日期
                        for (let i = timelineResults.length - 1; i >= 0; i--) {
                          const process = timelineResults[i];
                          const processDate = new Date(process.estimatedEnd);
                          
                          // 检查日期是否有效且不是"时效值为0"的情况
                          if (!isNaN(processDate.getTime()) && process.estimatedEnd !== '时效值为0') {
                            effectiveLastProcess = process;
                            lastCompletionDate = processDate;
                            break;
                          }
                        }
                        
                        // 如果没有找到有效的完成日期，使用最后一个流程
                        if (!effectiveLastProcess) {
                          effectiveLastProcess = timelineResults[timelineResults.length - 1];
                          lastCompletionDate = new Date(effectiveLastProcess.estimatedEnd);
                        }
                        
                        // 计算所有节点的总调整量（用于动态缓冲期计算）
                        const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
                        
                        // 计算动态缓冲期：基础14天 - 节点总调整量，最小为0天
      const baseBuferDays = baseBufferDays;
      const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                        
                        // 计算最后完成日期 + 动态缓冲期（考虑最后流程完成日期的调整）
                        const adjustedCompletionDate = new Date(lastCompletionDate);
                        adjustedCompletionDate.setDate(adjustedCompletionDate.getDate() + completionDateAdjustment);
                        
                        const deliveryDate = new Date(adjustedCompletionDate);
                        deliveryDate.setDate(deliveryDate.getDate() + dynamicBufferDays);
                        
                        // 计算交期余量
                        // 如果客户期望日期不为空：交期余量 = 客户期望日期 - (最后流程完成 + 缓冲期)
                        // 如果客户期望日期为空：交期余量 = (最后流程完成 + 缓冲期)
                        let timeDiff, baseDaysDiff, finalDaysDiff;
                        if (expectedDate) {
                          // 有客户期望日期：计算期望日期与交付日期的差值
                          timeDiff = expectedDate.getTime() - deliveryDate.getTime();
                          baseDaysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                        } else {
                          // 无客户期望日期：直接显示交付日期（最后流程完成 + 缓冲期）
                          const today = new Date();
                          today.setHours(0, 0, 0, 0);
                          timeDiff = deliveryDate.getTime() - today.getTime();
                          baseDaysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
                        }
                        
                        // 计算最终交期余量：基础余量 - 扣减天数
                        finalDaysDiff = baseDaysDiff - deliveryMarginDeductions;
                        
                        return (
                          <>
                            {expectedDate && (
                              <>
                                {/* 客户期望日期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    客户期望日期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#722ed1',
                                    display: 'block'
                                  }}>
                                    {formatDate(expectedDate)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(expectedDate)}
                                  </Text>
                                </div>
                                
                                {/* 减号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  -
                                </div>
                                
                                {/* 最后流程完成 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    {effectiveLastProcess === timelineResults[timelineResults.length - 1] 
                                      ? '最后流程完成' 
                                      : `有效流程完成 (${effectiveLastProcess.nodeName})`}
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#52c41a',
                                    display: 'block'
                                  }}>
                                    {formatDate(adjustedCompletionDate)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(adjustedCompletionDate)}
                                  </Text>
                                  {effectiveLastProcess !== timelineResults[timelineResults.length - 1] && (
                                    <Text style={{ fontSize: '11px', color: '#fa8c16', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (最后流程时效为0，使用此流程)
                                    </Text>
                                  )}
                                  {completionDateAdjustment > 0 && (
                                    <Text style={{ fontSize: '11px', color: '#1890ff', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (已调整 +{completionDateAdjustment}天)
                                    </Text>
                                  )}
                                </div>
                                
                                {/* 加号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  +
                                </div>
                                
                                {/* 缓冲期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    缓冲期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '20px', 
                                    fontWeight: 'bold',
                                    color: dynamicBufferDays < baseBufferDays ? '#ff4d4f' : '#fa8c16',
                                    display: 'block'
                                  }}>
                                    {dynamicBufferDays}天
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    固定缓冲
                                  </Text>
                                </div>
                                
                                {/* 等号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  =
                                </div>
                              </>
                            )}
                            
                            {!expectedDate && (
                              <>
                                {/* 最后流程完成 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    {effectiveLastProcess === timelineResults[timelineResults.length - 1] 
                                      ? '最后流程完成' 
                                      : `有效流程完成 (${effectiveLastProcess.nodeName})`}
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#52c41a',
                                    display: 'block'
                                  }}>
                                    {formatDate(effectiveLastProcess.estimatedEnd)}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(effectiveLastProcess.estimatedEnd)}
                                  </Text>
                                  {effectiveLastProcess !== timelineResults[timelineResults.length - 1] && (
                                    <Text style={{ fontSize: '11px', color: '#fa8c16', fontStyle: 'italic', display: 'block', marginTop: '2px' }}>
                                      (最后流程时效为0，使用此流程)
                                    </Text>
                                  )}
                                </div>
                                
                                {/* 加号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  +
                                </div>
                                
                                {/* 缓冲期 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    缓冲期
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '20px', 
                                    fontWeight: 'bold',
                                    color: dynamicBufferDays < baseBufferDays ? '#ff4d4f' : '#fa8c16',
                                    display: 'block'
                                  }}>
                                    {dynamicBufferDays}天
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    固定缓冲
                                  </Text>
                                </div>
                                
                                {/* 减号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  -
                                </div>
                                
                                {/* 今天 */}
                                <div style={{ textAlign: 'center' }}>
                                  <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                    今天
                                  </Text>
                                  <Text style={{ 
                                    fontSize: '16px', 
                                    fontWeight: 'bold',
                                    color: '#666',
                                    display: 'block'
                                  }}>
                                    {formatDate(new Date())}
                                  </Text>
                                  <Text style={{ fontSize: '12px', color: '#999' }}>
                                    {getDayOfWeek(new Date())}
                                  </Text>
                                </div>
                                
                                {/* 等号 */}
                                <div style={{ 
                                  fontSize: '24px', 
                                  fontWeight: 'bold', 
                                  color: '#1890ff',
                                  display: 'flex',
                                  alignItems: 'center'
                                }}>
                                  =
                                </div>
                              </>
                            )}
                            
                            {/* 交期余量结果 */}
                            <div style={{ 
                              textAlign: 'center',
                              padding: '12px',
                              backgroundColor: finalDaysDiff >= 0 ? '#f6ffed' : '#fff2f0',
                              borderRadius: '8px',
                              border: `2px solid ${finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f'}`
                            }}>
                              <Text strong style={{ display: 'block', fontSize: '14px', color: '#666', marginBottom: '4px' }}>
                                交期余量
                              </Text>
                              <Text style={{ 
                                fontSize: '24px', 
                                fontWeight: 'bold',
                                color: finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f',
                                display: 'block'
                              }}>
                                {finalDaysDiff >= 0 ? '+' : ''}{finalDaysDiff}天
                              </Text>
                              <Text style={{ 
                                fontSize: '12px', 
                                color: finalDaysDiff >= 0 ? '#52c41a' : '#ff4d4f',
                                fontWeight: 'bold'
                              }}>
                                {finalDaysDiff >= 0 ? '✅ 时间充裕' : '⚠️ 时间紧张'}
                              </Text>
                            </div>
                          </>
                        );
                      })()}
                    </div>
                    
                    <div style={{ 
                      padding: '12px',
                      backgroundColor: 'rgba(255, 255, 255, 0.6)',
                      borderRadius: '6px',
                      fontSize: '13px',
                      color: '#666',
                      lineHeight: '1.5'
                    }}>
                      {(() => {
                        // 计算动态缓冲期和总调整量
                        const totalAdjustments = Object.values(timelineAdjustments).reduce((sum, adj) => sum + adj, 0);
                        const baseBuferDays = baseBufferDays;
                        const dynamicBufferDays = Math.max(0, baseBuferDays - totalAdjustments);
                        
                        return (
                          <Text>
                            💡 <strong>说明：</strong>
                            {expectedDate 
                              ? `交期余量 = 客户期望日期 - (最后流程完成日期 + ${dynamicBufferDays}天缓冲期)`
                              : `交期余量 = (最后流程完成日期 + ${dynamicBufferDays}天缓冲期) - 今天`
                            }
                            <br />
                            {expectedDate 
                              ? '• 正值表示有充裕时间，负值表示可能延期'
                              : '• 显示预计交付日期距离今天的天数'
                            }
                            <br />
                            • 缓冲期 = 基础{baseBuferDays}天 - 节点调整总量（最小0天），包含质检、包装、物流等后续环节
                            {totalAdjustments > 0 && (
                              <>
                                <br />
                                • 当前节点总调整量：+{totalAdjustments}天，缓冲期相应减少
                              </>
                            )}
                          </Text>
                        );
                      })()}
                    </div>
                  </div>
                </Card>
              )}
              
              <div style={{ marginTop: '16px', padding: '12px', backgroundColor: '#f6f8fa', borderRadius: '6px' }}>
              <Text strong>📊 计算说明：</Text>
                <Text style={{ display: 'block', marginTop: '4px' }}>
                  共找到 {timelineResults.length} 个匹配的节点。时间按流程顺序计算，上一个节点的完成时间等于下一个节点的开始时间。每个节点使用其特定的休息日配置和计算方式进行工作日计算。
                </Text>
                <div style={{ marginTop: '8px', padding: '8px', backgroundColor: '#e6f7ff', borderRadius: '4px' }}>
                  <Text strong style={{ color: '#1890ff' }}>🗓️ 计算规则说明：</Text>
                  <Text style={{ display: 'block', marginTop: '4px', fontSize: '14px' }}>
                    • <strong>内部计算</strong>：按9小时工作制（9:00-18:00），超时自动顺延至下个工作日
                    <br />
                    • <strong>外部计算</strong>：按24小时制计算，适用于外部供应商等不受工作时间限制的节点
                    <br />
                    • 根据每个节点的休息日配置自动跳过相应的休息日
                    <br />
                    • 可为每个节点配置“跳过日期”，这些日期将不参与工作日计算
                    <br />
                    • 时效值以"工作日"为单位计算，确保预期时间的准确性
                    <br />
                    • 使用 +1/-1 按钮调整整天，+0.5/-0.5 按钮调整半天，系统会自动重新计算所有后续节点
                    <br />
                    • 不同节点可配置不同的休息日和计算方式（如：内部节点按工作时间，外部节点按自然时间）
                  </Text>
                </div>
                {Object.keys(timelineAdjustments).length > 0 && (
                  <div style={{ marginTop: '8px', padding: '8px', backgroundColor: '#fff7e6', borderRadius: '4px' }}>
                    <Text strong style={{ color: '#fa8c16' }}>当前调整：</Text>
                    <div style={{ marginTop: '4px' }}>
                      {Object.entries(timelineAdjustments).map(([nodeIndex, adjustment]) => {
                        const nodeName = timelineResults[parseInt(nodeIndex)]?.nodeName;
                        return (
                          <Text key={nodeIndex} style={{ display: 'block', fontSize: '12px' }}>
                            {nodeName}: {adjustment > 0 ? '+' : ''}{adjustment.toFixed(1)} 天
                          </Text>
                        );
                      })}
                    </div>
                  </div>
                )}
              </div>
            </div>
          )}
        </div>
      </Modal>
      

      
      {/* 标签选择部分，仅在生成模式显示 */}
      {mode === 'generate' && labelOptions && Object.keys(labelOptions).length > 0 && (
        <Card title="标签选择" className="card-enhanced" style={{ marginBottom: '24px' }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '16px' }}>
            {Array.from({ length: 10 }, (_, i) => i + 1).map(num => {
              const labelKey = `标签${num}`;
              const options = labelOptions[labelKey] || [];
              const isMultiSelect = labelKey === '标签7' || labelKey === '标签8' || labelKey === '标签10';
              
              return (
                <div key={labelKey}>
                  <Text strong style={{ display: 'block', marginBottom: '8px' }}>{labelKey}</Text>
                  <Select
                    className="select-enhanced"
                    style={{ width: '100%' }}
                    placeholder={`请选择${labelKey}或输入关键字搜索`}
                    value={selectedLabels[labelKey]}
                    onChange={(value) => handleLabelChange(labelKey, value)}
                    multiple={isMultiSelect}
                    filter
                    showSearch
                  >
                    {options.map((option, optionIndex) => (
                      <Select.Option key={optionIndex} value={option.value}>
                        {option.label}
                      </Select.Option>
                    ))}
                  </Select>
                </div>
              );
            })}
          </div>
          
          {/* 客户期望日期选择 */}
          <div style={{ marginTop: '24px' }}>
            <Text strong style={{ display: 'block', marginBottom: '8px' }}>客户期望日期</Text>
            <DatePicker
              className="input-enhanced"
              style={{ width: '300px' }}
              placeholder="请选择客户期望日期"
              value={expectedDate}
              onChange={(date) => setExpectedDate(date)}
              format="yyyy-MM-dd"
              disabledDate={(date) => {
                // 禁用今天之前的日期
                const today = new Date();
                today.setHours(0, 0, 0, 0);
                return date < today;
              }}
            />
            {expectedDate && (
              <Text type="secondary" style={{ marginLeft: '12px' }}>
                已选择：{formatDate(expectedDate, 'CHINESE_DATE')}
              </Text>
            )}
          </div>
          
          {Object.keys(selectedLabels).length > 0 && (
            <div style={{ 
              marginTop: '24px', 
              padding: '20px',
              background: 'linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%)',
              borderRadius: '12px',
              border: '1px solid #bae6fd'
            }}>
              <Space direction="vertical" size="large" style={{ width: '100%' }}>
                <Button 
                  type='primary'
                  className="btn-gradient-calculate"
                  size="large"
                  onClick={handleCalculateTimeline}
                  loading={timelineLoading}
                  disabled={timelineLoading}
                  style={{ minWidth: '160px' }}
                >
                  计算预计时间
                </Button>
                <Text type="secondary" style={{ fontSize: '14px' }}>
                  已选择 {Object.keys(selectedLabels).length} 个标签
                </Text>
              </Space>
              
              <div style={{ marginTop: '16px' }}>
                <Text strong style={{ color: '#0369a1' }}>当前选择的标签：</Text>
                <div style={{ marginTop: '8px', display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
                  {Object.entries(selectedLabels).map(([key, value]) => {
                    const displayValue = Array.isArray(value) ? value.join(', ') : value;
                    return (
                      <span 
                        key={key}
                        style={{
                          background: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)',
                          color: 'white',
                          padding: '4px 12px',
                          borderRadius: '20px',
                          fontSize: '12px',
                          fontWeight: 500
                        }}
                      >
                        {key}: {displayValue}
                      </span>
                    );
                  })}
                </div>
              </div>
            </div>
          )}
        </Card>
      )}

      {mode === 'batch' && (
        <main className="main" style={{ padding: '20px' }}>
          {/* 批量处理配置 */}
          <div className="batch-config-card" style={{ 
              background: 'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)', 
              padding: '24px', 
              borderRadius: '16px', 
              border: '1px solid #e2e8f0',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.05)',
              marginTop: '16px'
            }}>
              <Title heading={4} style={{ marginBottom: '20px', color: '#334155' }}>
                批量处理配置
              </Title>
              <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
                {/* 第一行：表和视图选择 */}
                <div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>数据表:</Text>
                    <Select
                      value={selectedBatchTableId}
                      onChange={handleBatchTableChange}
                      placeholder="请选择表"
                      loading={tablesLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                    >
                      {availableTables.map(table => (
                        <Select.Option key={table.id} value={table.id}>
                          {table.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>视图:</Text>
                    <Select
                      value={selectedBatchViewId}
                      onChange={(value) => setSelectedBatchViewId(value)}
                      placeholder="请选择视图（可选）"
                      loading={viewsLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                      allowClear
                    >
                      {availableViews.map(view => (
                        <Select.Option key={view.id} value={view.id}>
                          {view.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                </div>
                
                {/* 第二行：处理行数和操作按钮 */}
                <div style={{ display: 'flex', gap: '20px', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569' }}>处理行数:</Text>
                    <InputNumber 
                      value={batchRowCount} 
                      onChange={(value) => setBatchRowCount(value || 10)}
                      min={1}
                      max={100}
                      style={{ width: 100 }}
                    />
                  </div>
                  
                  <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                    {batchProcessing && (
                      <div style={{ 
                        display: 'flex', 
                        alignItems: 'center', 
                        gap: '8px',
                        background: 'rgba(59, 130, 246, 0.1)',
                        padding: '8px 16px',
                        borderRadius: '8px',
                        border: '1px solid rgba(59, 130, 246, 0.2)'
                      }}>
                        <div style={{
                          width: '12px',
                          height: '12px',
                          borderRadius: '50%',
                          background: 'conic-gradient(from 0deg, #3b82f6, transparent)',
                          animation: 'spin 1s linear infinite'
                        }}></div>
                        <Text style={{ color: '#3b82f6', fontWeight: 500 }}>
                          进度: {batchProgress.current}/{batchProgress.total}
                        </Text>
                      </div>
                    )}
                    <Button 
                      type="primary" 
                      theme="solid"
                      size="large"
                      loading={batchProcessing}
                      onClick={() => handleBatchProcess(batchRowCount)}
                      disabled={batchProcessing || !selectedBatchTableId}
                      style={{
                        background: selectedBatchTableId ? 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' : undefined,
                        border: 'none',
                        borderRadius: '12px',
                        padding: '12px 24px',
                        fontWeight: 600,
                        boxShadow: selectedBatchTableId ? '0 4px 12px rgba(59, 130, 246, 0.3)' : undefined
                      }}
                    >
                      {batchProcessing ? '批量处理中...' : '开始批量生成'}
                    </Button>
                  </div>
                </div>
              </div>
            </div>
        </main>
      )}
      
      {mode === 'generate' && (
        <main className="main" style={{ padding: '20px' }}>
          <Card className="card-enhanced">
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '24px' }}>
              <div>
                <Title heading={3} style={{ 
                  margin: 0,
                  background: 'linear-gradient(135deg, #1890ff 0%, #722ed1 100%)',
                  WebkitBackgroundClip: 'text',
                  WebkitTextFillColor: 'transparent',
                  backgroundClip: 'text'
                }}>版单数据</Title>
                <Text type='secondary' style={{ fontSize: '14px', marginTop: '4px' }}>
                  选择需要生成时效的版单记录
                </Text>
                {selectedRecords.length > 0 && (
                  <Text type='secondary' style={{ fontSize: '12px', marginTop: '4px' }}>
                    已选择 {selectedRecords.length} 条记录
                  </Text>
                )}
              </div>
              
              <Space>
                <Button 
                  type='primary' 
                  className="btn-gradient-select"
                  size="large"
                  onClick={handleSelectRecords}
                  loading={loading}
                  disabled={loading}
                >
                  {selectedRecords.length > 0 ? '重新选择' : '选择记录'}
                </Button>
                
                {selectedRecords.length > 0 && (
                  <Button 
                    type='secondary' 
                    onClick={handleClearRecords}
                    size='small'
                  >
                    清空选择
                  </Button>
                )}
              </Space>
            </div>
            
            {/* 已选择记录的详细信息 */}
            {selectedRecords.length > 0 && recordDetails.length > 0 && (
              <div style={{ 
                padding: '16px', 
                background: 'linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%)', 
                borderRadius: '12px',
                border: '1px solid #dee2e6',
                marginBottom: '20px',
                boxShadow: '0 2px 8px rgba(0,0,0,0.06)'
              }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
                  <div>
                    <Text strong style={{ color: '#495057' }}>主记录:</Text>
                    <span style={{ 
                      marginLeft: '8px', 
                      fontSize: '12px',
                      background: 'linear-gradient(135deg, #007bff 0%, #0056b3 100%)',
                      color: 'white',
                      padding: '2px 8px',
                      borderRadius: '12px',
                      fontWeight: 500
                    }}>
                      {recordDetails[0].displayValue || recordDetails[0].id}
                    </span>
                  </div>
                  {recordDetails.length > 1 && (
                    <div>
                      <Text type='secondary'>+ 其他 {recordDetails.length - 1} 条</Text>
                    </div>
                  )}
                </div>
              </div>
            )}
            
            {/* 加载状态 */}
            {loading && (
              <div style={{ textAlign: 'center', padding: '20px' }}>
                <Spin size="large" />
                <div style={{ marginTop: '10px' }}>
                  <Text>正在加载版单数据...</Text>
                </div>
              </div>
            )}
            
            {/* 空状态提示 */}
            {selectedRecords.length === 0 && !loading && (
              <div style={{ 
                textAlign: 'center', 
                padding: '20px', 
                backgroundColor: '#fafafa',
                borderRadius: '6px',
                border: '1px dashed #d9d9d9'
              }}>
                <Text type="tertiary">请选择版单记录开始操作</Text>
              </div>
            )}
          </Card>
          
          {/* 批量处理配置 - 移动到版单数据下方 */}
          {mode === 'batch' && (
            <div className="batch-config-card" style={{ 
              background: 'linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)', 
              padding: '24px', 
              borderRadius: '16px', 
              border: '1px solid #e2e8f0',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.05)',
              marginTop: '16px'
            }}>
              <Title heading={4} style={{ marginBottom: '20px', color: '#334155' }}>
                批量处理配置
              </Title>
              <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
                {/* 第一行：表和视图选择 */}
                <div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>数据表:</Text>
                    <Select
                      value={selectedBatchTableId}
                      onChange={handleBatchTableChange}
                      placeholder="请选择表"
                      loading={tablesLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                    >
                      {availableTables.map(table => (
                        <Select.Option key={table.id} value={table.id}>
                          {table.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0',
                    minWidth: '280px'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569', minWidth: '60px' }}>视图:</Text>
                    <Select
                      value={selectedBatchViewId}
                      onChange={(value) => setSelectedBatchViewId(value)}
                      placeholder="请选择视图（可选）"
                      loading={viewsLoading}
                      style={{ flex: 1, minWidth: '180px' }}
                      allowClear
                    >
                      {availableViews.map(view => (
                        <Select.Option key={view.id} value={view.id}>
                          {view.name}
                        </Select.Option>
                      ))}
                    </Select>
                  </div>
                </div>
                
                {/* 第二行：处理行数和操作按钮 */}
                <div style={{ display: 'flex', gap: '20px', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap' }}>
                  <div className="batch-input-group" style={{ 
                    display: 'flex', 
                    alignItems: 'center', 
                    gap: '8px',
                    background: 'white',
                    padding: '12px 16px',
                    borderRadius: '12px',
                    border: '1px solid #e2e8f0'
                  }}>
                    <Text style={{ fontWeight: 500, color: '#475569' }}>处理行数:</Text>
                    <InputNumber 
                      value={batchRowCount} 
                      onChange={(value) => setBatchRowCount(value || 10)}
                      min={1}
                      max={100}
                      style={{ width: 100 }}
                    />
                  </div>
                  
                  <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                    {batchProcessing && (
                      <div style={{ 
                        display: 'flex', 
                        alignItems: 'center', 
                        gap: '8px',
                        background: 'rgba(59, 130, 246, 0.1)',
                        padding: '8px 16px',
                        borderRadius: '8px',
                        border: '1px solid rgba(59, 130, 246, 0.2)'
                      }}>
                        <div style={{
                          width: '12px',
                          height: '12px',
                          borderRadius: '50%',
                          background: 'conic-gradient(from 0deg, #3b82f6, transparent)',
                          animation: 'spin 1s linear infinite'
                        }}></div>
                        <Text style={{ color: '#3b82f6', fontWeight: 500 }}>
                          进度: {batchProgress.current}/{batchProgress.total}
                        </Text>
                      </div>
                    )}
                    <Button 
                      type="primary" 
                      theme="solid"
                      size="large"
                      loading={batchProcessing}
                      onClick={() => handleBatchProcess(batchRowCount)}
                      disabled={batchProcessing || !selectedBatchTableId}
                      style={{
                        background: selectedBatchTableId ? 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' : undefined,
                        border: 'none',
                        borderRadius: '12px',
                        padding: '12px 24px',
                        fontWeight: 600,
                        boxShadow: selectedBatchTableId ? '0 4px 12px rgba(59, 130, 246, 0.3)' : undefined
                      }}
                    >
                      {batchProcessing ? '批量处理中...' : '开始批量生成'}
                    </Button>
                  </div>
                </div>
              </div>
            </div>
          )}
        </main>
      )}
      {mode === 'generate' && (
        <>
          {/* 面料数据查询结果 */}
          {queryResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>面料数据查询结果 ({queryResults.length} 条)</Title>
              <Table 
                columns={columns} 
                dataSource={queryResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
          {/* 二次工艺查询结果 */}
          {secondaryProcessResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>二次工艺查询结果 ({secondaryProcessResults.length} 条)</Title>
              <Table 
                columns={secondaryProcessColumns} 
                dataSource={secondaryProcessResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
          {/* 工艺价格查询结果 */}
          {pricingDetailsResults.length > 0 && (
            <>
              <Divider />
              <Title heading={4}>工艺价格查询结果 ({pricingDetailsResults.length} 条)</Title>
              <Table 
                columns={pricingDetailsColumns} 
                dataSource={pricingDetailsResults.map((item, index) => ({ ...item, key: index }))}
                pagination={{ pageSize: 10 }}
                style={{ marginTop: '10px' }}
              />
            </>
          )}
        </>
      )}
    </div>
  );
}