/*
 * @Author: code4eat awesomedema@gmail.com
 * @Date: 2023-03-03 11:30:33
 * @LastEditors: code4eat awesomedema@gmail.com
 * @LastEditTime: 2025-10-30 10:24:16
 * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

import KCIMPagecontainer from '@/components/KCIMPageContainer';
import { KCIMTable } from '@/components/KCIMTable';

import { createFromIconfontCN } from '@ant-design/icons';

import { ActionType, ProFormInstance } from '@ant-design/pro-components';
import { ModalForm } from '@ant-design/pro-form';
import { ProColumns } from '@ant-design/pro-table';
import {
  Modal,
  message,
  Drawer,
  Tabs,
  Input,
  DatePicker,
  Popover,
  Alert,
  Skeleton,
} from 'antd';
import { Key, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import * as XLSX from 'xlsx-js-style';
import { saveAs } from 'file-saver';
import moment from 'moment';
import 'moment/locale/zh-cn';
import locale from 'antd/es/date-picker/locale/zh_CN';

import {
  addData,
  computeProfitReq,
  getReportDataReq,
  getReportProjectSettingList,
  getResponsibleCenters,
  saveReportRelation,
} from './service';

import './style.less';

import React from 'react';

import { getDicDataBySysId, getParamsDataBySysId } from '@/services/getDic';
import { KCIMLeftList } from '@/components/KCIMLeftList';
import { formatMoneyNumber } from '@/utils/format';
import { useModel } from '@umijs/max';
import { getUserHasReports } from '@/pages/costAccounting/calcPageTemplate/service';

const IconFont = createFromIconfontCN({
  scriptUrl: '',
});

const getRawReportFontColor = (record: any) => {
  const rawColor =
    record?.fontColor ||
    record?.fontcolor ||
    record?.font_color ||
    record?.color ||
    record?.font;
  if (typeof rawColor !== 'string') return undefined;
  const color = rawColor.trim().replace(/^['"]|['"]$/g, '');
  if (!color) return undefined;
  return color;
};

const toHex2 = (num: number) =>
  Math.max(0, Math.min(255, Math.round(num)))
    .toString(16)
    .padStart(2, '0')
    .toUpperCase();

const cssColorCache = new Map<string, string | undefined>();

const convertToExcelRgb = (rawColor: any) => {
  if (typeof rawColor !== 'string') return undefined;
  const color = rawColor.trim().replace(/^['"]|['"]$/g, '');
  if (!color) return undefined;
  if (cssColorCache.has(color)) return cssColorCache.get(color);
  const hexColorMatch = color.match(
    /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,
  );
  if (hexColorMatch) {
    const hex = hexColorMatch[1];
    if (hex.length === 3) {
      const r = hex[0] + hex[0];
      const g = hex[1] + hex[1];
      const b = hex[2] + hex[2];
      const result = (r + g + b).toUpperCase();
      cssColorCache.set(color, result);
      return result;
    }
    if (hex.length === 6) {
      const result = hex.toUpperCase();
      cssColorCache.set(color, result);
      return result;
    }
    // #RRGGBBAA 忽略 alpha，取 RRGGBB，兼容更多表格软件
    const result = hex.slice(0, 6).toUpperCase();
    cssColorCache.set(color, result);
    return result;
  }

  const rgbaMatch = color.match(
    /^rgba?\(\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)\s*(?:,\s*([0-9.]+)\s*)?\)$/i,
  );
  if (rgbaMatch) {
    const r = Number(rgbaMatch[1]);
    const g = Number(rgbaMatch[2]);
    const b = Number(rgbaMatch[3]);
    const result = `${toHex2(r)}${toHex2(g)}${toHex2(b)}`;
    cssColorCache.set(color, result);
    return result;
  }

  // 兜底：交给浏览器解析命名色/hsl 等 CSS 颜色格式
  if (typeof document !== 'undefined') {
    const temp = document.createElement('span');
    temp.style.color = '';
    temp.style.color = color;
    if (temp.style.color) {
      temp.style.display = 'none';
      document.body.appendChild(temp);
      const computed = window.getComputedStyle(temp).color;
      document.body.removeChild(temp);
      const computedMatch = computed.match(
        /^rgba?\(\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)\s*(?:,\s*([0-9.]+)\s*)?\)$/i,
      );
      if (computedMatch) {
        const r = Number(computedMatch[1]);
        const g = Number(computedMatch[2]);
        const b = Number(computedMatch[3]);
        const result = `${toHex2(r)}${toHex2(g)}${toHex2(b)}`;
        cssColorCache.set(color, result);
        return result;
      }
    }
  }

  cssColorCache.set(color, undefined);
  return undefined;
};

const DEFAULT_IGNORED_EXCEL_RGB = new Set(['000000', '17181A']);
const pickMeaningfulColor = (excelRgb?: string) =>
  excelRgb && !DEFAULT_IGNORED_EXCEL_RGB.has(excelRgb) ? excelRgb : undefined;

const collectRenderedRowColorMap = () => {
  const rowColorMap = new Map<string, string>();
  if (typeof document === 'undefined') return rowColorMap;

  const rows = document.querySelectorAll(
    '.departmentCostCalcReportTable .cost-ant-table-body .cost-ant-table-row[data-row-key], .departmentCostCalcReportTable .virtual-table-row[data-row-key]',
  );

  rows.forEach((rowNode) => {
    const row = rowNode as HTMLElement;
    const rowKey = row.getAttribute('data-row-key');
    if (!rowKey) return;

    const rowStyle = window.getComputedStyle(row);
    const cssVarColor = rowStyle.getPropertyValue('--report-font-color').trim();
    const firstCell = row.querySelector(
      'td, .virtual-table-cell',
    ) as HTMLElement | null;
    const renderedColor = firstCell
      ? window.getComputedStyle(firstCell).color
      : '';
    const finalColor = cssVarColor || renderedColor;
    if (finalColor) {
      const excelRgb = pickMeaningfulColor(convertToExcelRgb(finalColor));
      if (excelRgb) {
        rowColorMap.set(rowKey, excelRgb);
      }
    }
  });

  return rowColorMap;
};

const buildTitleColumnColorMap = (
  title: any[],
  keyName: 'reportName' | 'responsibilityName',
) => {
  const map: Record<string, string> = {};

  const getChildren = (node: any) => {
    if (Array.isArray(node?.childTitle) && node.childTitle.length > 0)
      return node.childTitle;
    if (Array.isArray(node?.child) && node.child.length > 0) return node.child;
    return [];
  };

  const walk = (nodes: any[], inheritedColor?: string) => {
    nodes.forEach((node) => {
      const currentColor = getRawReportFontColor(node) || inheritedColor;
      const children = getChildren(node);
      if (children.length > 0) {
        walk(children, currentColor);
        return;
      }

      const key =
        keyName === 'responsibilityName'
          ? node?.responsibilityCode
          : node?.reportId;
      if (key !== undefined && key !== null && currentColor) {
        map[String(key)] = currentColor;
      }
    });
  };

  walk(title || []);
  return map;
};

const yieldToBrowser = () =>
  new Promise<void>((resolve) => {
    if (
      typeof window === 'undefined' ||
      typeof window.requestAnimationFrame !== 'function'
    ) {
      setTimeout(resolve, 0);
      return;
    }
    window.requestAnimationFrame(() => resolve());
  });
function findAllParentKeys(tree: any[]) {
  const parentKeys: Key[] = [];

  function traverse(nodes: any[]) {
    for (const node of nodes) {
      if (node.children && node.children.length > 0) {
        parentKeys.push(node.id);
        traverse(node.children);
      }
    }
  }

  traverse(tree);
  return parentKeys;
}

function findFirstLevelParentKeys(tree: any[]) {
  return tree
    .filter((node) => node.children && node.children.length > 0)
    .map((node) => node.id);
}

function countLeafNodes(trees: any[]) {
  let leafCount = 0;

  // 遍历集合中的每棵树
  for (let i = 0; i < trees.length; i++) {
    leafCount += countLeafNodesRecursive(trees[i]);
  }

  return leafCount;
}

function countLeafNodesRecursive(node: any) {
  // 如果当前节点没有子节点，说明它是一个叶子节点
  if (!node.children || node.children.length === 0) {
    return 1;
  }

  let leafCount = 0;

  // 递归计算每个子节点的叶子节点数
  for (let i = 0; i < node.children.length; i++) {
    leafCount += countLeafNodesRecursive(node.children[i]);
  }

  return leafCount;
}

function searchTree(tree: any[], searchTerm: string) {
  // 定义结果数组
  let results = [];

  // 定义递归函数来搜索匹配的节点
  function searchNode(node: any) {
    // 创建一个变量来标记当前节点或其子节点是否匹配
    let isMatch = false;

    // 检查当前节点的 name 或 code 是否包含搜索词
    if (node.reportName.includes(searchTerm)) {
      isMatch = true;
    }

    // 复制当前节点，避免修改原始数据
    let newNode = { ...node, children: [] };

    // 如果有子节点，递归搜索每个子节点
    if (node.children) {
      for (let child of node.children) {
        let childMatch = searchNode(child);
        // 如果子节点或其子树匹配，添加到新节点的子节点数组中
        if (childMatch) {
          newNode.children.push(childMatch);
          isMatch = true;
        }
      }
    }

    // 如果当前节点或其任何子节点匹配，返回新节点
    // 如果children为空，则不包含children属性
    if (isMatch) {
      if (newNode.children.length === 0) {
        delete newNode.children;
      }
      return newNode;
    } else {
      return null;
    }
  }

  // 遍历树的每个顶级节点
  for (let node of tree) {
    let result = searchNode(node);
    if (result) {
      results.push(result);
    }
  }

  return results;
}

function processTree(originalData: any[]) {
  return (originalData || []).map((node) => {
    const nextNode = {
      ...node,
      id:
        node.id ||
        node.responsibilityCode ||
        node.reportId ||
        Math.random().toString(36).substr(2, 9),
    };

    if (Array.isArray(node.profitList)) {
      node.profitList.forEach((profit: any) => {
        if (profit?.reportId !== undefined) {
          nextNode[`${profit.reportId}`] = profit.value;
        }
      });
    }

    if (Array.isArray(node.child) && node.child.length > 0) {
      nextNode.children = processTree(node.child);
    }

    return nextNode;
  });
}

const EMPTY_STYLE_OBJ = {};
// 递归函数，用于处理多层级标题
function generateColumns(
  item: any,
  titleIndex = 0,
  title: string,
  hideRatioColumns = false,
  inheritedFontColor?: string,
) {
  // // 检查是否需要隐藏"占比"列，如果title包含"占比"，且hideRatioColumns为true，则返回null
  // if (hideRatioColumns && item[`${title}`].includes('占比')) {
  //     return null;
  // }

  const currentFontColor = getRawReportFontColor(item) || inheritedFontColor;
  const columnCellStyle = currentFontColor
    ? { color: currentFontColor }
    : undefined;
  const cellProps = columnCellStyle
    ? { style: columnCellStyle }
    : EMPTY_STYLE_OBJ;

  const column: any =
    title == 'responsibilityName'
      ? {
          title: item[`${title}`],
          dataIndex: `${item.responsibilityCode}`,
          key: `${item.responsibilityCode}`,
          fontColor: item?.fontColor || item?.fontcolor || item?.font_color,
          onCell: () => cellProps,
          onHeaderCell: () => cellProps,
          align:
            item.responsibilityCode.indexOf('amount') != -1 ? 'right' : 'right',
          ellipsis: true,
          renderText(num: number, record: any) {
            if (item.responsibilityCode.indexOf('amount') != -1) {
              const { permil, decimalPlace, dataType } = record;
              if (typeof num === 'number' && !isNaN(num)) {
                // 根据 dataType 判断渲染类型
                if (dataType === 2) {
                  // 百分比类型
                  return `${(num * 100).toFixed(decimalPlace || 2)}%`;
                } else {
                  // 数值类型 (dataType === 1 或未定义)
                  // 根据 permil 字段决定是否使用千位分隔符
                  const useGrouping = permil === 1;

                  // 解析 decimalPlace 字段，如果无效或未定义，则默认为2
                  let fractionDigits = parseInt(decimalPlace, 10);
                  if (isNaN(fractionDigits) || fractionDigits < 0) {
                    fractionDigits = 2; // 默认保留两位小数
                  }

                  return num.toLocaleString('en-US', {
                    minimumFractionDigits: fractionDigits,
                    maximumFractionDigits: fractionDigits,
                    useGrouping: useGrouping,
                  });
                }
              } else {
                // 对于非数字或 null/undefined，返回空
                return '';
              }
            } else {
              return num;
            }
          },
        }
      : {
          title: item[`${title}`],
          ellipsis: true,
          dataIndex: `${item[`reportId`]}`,
          key: `${item[`reportId`]}`,
          fontColor: item?.fontColor || item?.fontcolor || item?.font_color,
          onCell: () => cellProps,
          onHeaderCell: () => cellProps,
          align: 'right',
          // 新增：根据 dataType 渲染不同格式
          renderText(num: string) {
            // 使用 parseFloat 来保持数字精度
            const value = parseFloat(num);
            const { permil, decimalPlace, dataType } = item;

            // 检查 value 是否为有效数字
            if (typeof value === 'number' && !isNaN(value)) {
              if (dataType === 2) {
                // 百分比类型，保留 decimalPlace 位小数
                return `${(value * 100).toFixed(decimalPlace || 2)}%`;
              } else {
                // 数值类型 (dataType === 1 或未定义)
                // 根据 permil 字段决定是否使用千位分隔符
                const useGrouping = permil === 1;
                // 解析 decimalPlace 字段，如果无效或未定义，则默认为2
                let fractionDigits = parseInt(decimalPlace, 10);
                if (isNaN(fractionDigits) || fractionDigits < 0) {
                  fractionDigits = 2; // 默认保留两位小数
                }
                // 返回格式化后的数字
                return value.toLocaleString('en-US', {
                  minimumFractionDigits: fractionDigits,
                  maximumFractionDigits: fractionDigits,
                  useGrouping: useGrouping,
                });
              }
            } else {
              // 非数字或 null/undefined 返回空
              return '';
            }
          },
        };

  // 强制以渲染层包裹颜色，避免被表格内部默认字体色覆盖
  column.render = (_: any, record: any) => {
    const value = record?.[column.dataIndex];
    const text = column.renderText ? column.renderText(value, record) : value;
    if (!currentFontColor) return text;
    return <span style={{ color: currentFontColor }}>{text}</span>;
  };

  // 递归处理子列
  if (
    item.childTitle &&
    Array.isArray(item.childTitle) &&
    item.childTitle.length > 0
  ) {
    column.children = item.childTitle
      .map((a: any, aindex: number) =>
        generateColumns(
          a,
          titleIndex + 1,
          title,
          hideRatioColumns,
          currentFontColor,
        ),
      )
      .filter((col: any) => col !== null); // 过滤掉null项
  }
  if (item.child && Array.isArray(item.child) && item.child.length > 0) {
    column.children = item.child
      .map((a: any, aindex: number) =>
        generateColumns(
          a,
          titleIndex + 1,
          title,
          hideRatioColumns,
          currentFontColor,
        ),
      )
      .filter((col: any) => col !== null); // 过滤掉null项
  }

  return column;
}

function transformTreeData(tree: any[]) {
  return (tree || []).map((node) => {
    const nextNode = {
      ...node,
      id:
        node.id ||
        node.responsibilityCode ||
        node.reportId ||
        Math.random().toString(36).substr(2, 9),
    };

    if (Array.isArray(node.data)) {
      node.data.forEach((item: any) => {
        if (item?.code && item.value !== undefined) {
          nextNode[item.code] = item.value;
        }
      });
    }

    if (Array.isArray(node.children) && node.children.length > 0) {
      nextNode.children = transformTreeData(node.children);
    }

    return nextNode;
  });
}

const getNextUnexpandedKeys = (
  data: any[],
  expandedKeys: Iterable<any> = [],
) => {
  const expandedKeySet =
    expandedKeys instanceof Set ? expandedKeys : new Set(expandedKeys);
  let keys: any[] = [];

  const traverse = (nodes: any) => {
    for (const node of nodes) {
      // 如果当前节点还没有展开，就把它加入 keys
      if (!expandedKeySet.has(node.id)) {
        keys.push(node.id);
      }

      // 如果当前节点已经展开，继续遍历子节点
      if (node.children && expandedKeySet.has(node.id)) {
        traverse(node.children);
      }
    }
  };

  traverse(data);

  return keys;
};

import { VirtualRow } from '@/components/KCIMTable/VirtualRow';

const drawerVirtualComponents = {
  body: {
    row: VirtualRow,
  },
};

export default function DepartmentCostCalc() {
  const [tableDataFilterParams, set_tableDataFilterParams] = useState<
    any | undefined
  >({ reportType: 0 });
  const tableRef = useRef<ActionType>();
  const formRef = useRef<ProFormInstance>();
  const [tabs, set_tabs] = useState<any[]>([]);

  const { initialState, setInitialState } = useModel('@@initialState');
  const [computeDate, set_computeDate] = useState<string>(
    initialState ? initialState.computeDate : '',
  );
  const [responsibleCenters, set_responsibleCenters] = useState<any[]>([]);
  const [currentTabKey, set_currentTabKey] = useState<any | undefined>(
    undefined,
  );
  const [currentTab, set_currentTab] = useState<any | undefined>(undefined);
  const [currentSelectedRespon, set_currentSelectedRespon] = useState<
    any | undefined
  >(undefined);
  const [tableDataSearchKeywords, set_tableDataSearchKeywords] = useState('');
  const [allParentsKeys, set_allParentsKeys] = useState<Key[]>([]);
  const [drawerTableVisible, set_drawerTableVisible] = useState(false);
  const [mainTableDataSource, set_mainTableDataSource] = useState<any[]>([]);
  const [drawerDataSource, set_drawerDataSource] = useState<any[]>([]);
  const [drawerExpandedKeys, set_drawerExpandedKeys] = useState<Key[]>([]);
  const [tableColumns, set_tableColumns] = useState<any[]>([]);
  const [calcResultText, set_calcResultText] = useState<undefined | string>(
    undefined,
  );
  const [loadingtransform, set_loadingtransform] = useState(false);
  const [ifShowPercent, set_ifShowPercent] = useState(true);
  const [titleColumnColorMap, set_titleColumnColorMap] = useState<
    Record<string, string>
  >({});

  const columns = useMemo<ProColumns[]>(
    () => [
      {
        title: '报表项目名称',
        dataIndex: 'reportName',
        width: '50%',
        ellipsis: true,
        renderText(text, record, index, action) {
          const { description } = record;
          return description ? (
            <Popover
              content={() => (
                <div dangerouslySetInnerHTML={{ __html: description }} />
              )}
            >
              <span style={{ cursor: 'pointer' }}>{text}</span>
              <IconFont
                className="hover-icon"
                style={{
                  fontSize: 16,
                  color: '#17181a',
                  paddingLeft: 4,
                  position: 'relative',
                  top: 1,
                }}
                type={'iconshuoming'}
              />
            </Popover>
          ) : (
            text
          );
        },
      },
      {
        title: '金额(元)',
        align: 'right',
        dataIndex: 'amount',
        renderText(num, record) {
          const { calcType, permil, decimalPlace, dataType } = record;
          if (record.children && calcType == '0') {
            return <React.Fragment></React.Fragment>;
          } else {
            // 检查 num 是否是有效数字
            if (typeof num === 'number' && !isNaN(num)) {
              // 根据 dataType 判断渲染类型
              if (dataType === 2) {
                // 百分比类型
                return `${(num * 100).toFixed(decimalPlace || 2)}%`;
              } else {
                // 数值类型 (dataType === 1 或未定义)
                // 根据 permil 字段决定是否使用千位分隔符
                const useGrouping = permil === 1;

                // 解析 decimalPlace 字段，如果无效或未定义，则默认为2
                let fractionDigits = parseInt(decimalPlace, 10);
                if (isNaN(fractionDigits) || fractionDigits < 0) {
                  fractionDigits = 2; // 默认保留两位小数
                }

                return num.toLocaleString('en-US', {
                  minimumFractionDigits: fractionDigits,
                  maximumFractionDigits: fractionDigits,
                  useGrouping: useGrouping,
                });
              }
            } else {
              // 对于非数字或 null/undefined，返回空
              return '';
            }
          }
        },
      },
      {
        title: '占比',
        align: 'right',
        hideInTable: !ifShowPercent,
        dataIndex: 'percent',
        renderText(num, record) {
          const { calcType, decimalPlace } = record;
          if (record.children && calcType == '0') {
            return <React.Fragment></React.Fragment>;
          } else {
            return num != null ? `${(num * 100).toFixed(decimalPlace)}%` : num;
          }
        },
      },
    ],
    [ifShowPercent],
  );

  // 主函数，生成表格列
  const generateTableColumns = useCallback(
    (title: any[], titleKeyName: string) => {
      return title.map((item: any, titleIndex: number) =>
        generateColumns(item, titleIndex, titleKeyName, !ifShowPercent),
      );
    },
    [ifShowPercent],
  );

  const getTableData = useCallback(
    async (params: any) => {
      const { responsibilityCode, filter = undefined } = params;
      if (!responsibilityCode) return [];
      const resp = await getReportProjectSettingList({ ...params });

      if (resp) {
        if (filter) {
          const filterData = searchTree(resp, filter);
          set_allParentsKeys(findAllParentKeys(filterData));
          set_mainTableDataSource([...filterData]);
          return {
            data: filterData,
            success: true,
          };
        }
        if (currentTab?.value == '1') {
          set_allParentsKeys(findFirstLevelParentKeys(resp));
        }
        set_mainTableDataSource([...resp]);

        return {
          data: resp,
          success: true,
        };
      }
      return [];
    },
    [currentTab?.value],
  );

  const getIfshowPercent = async () => {
    const { systemId } = JSON.parse(
      localStorage.getItem('currentSelectedTab') as string,
    );
    const resp = await getParamsDataBySysId(systemId, '1851077044079824896');
    if (resp) {
      set_ifShowPercent(resp.value == '1' ? true : false);
    }
  };

  const onTabChanged = (key: Key) => {
    set_currentTabKey(key);
    const needItem = tabs.filter((a) => a.key == key);
    if (needItem.length > 0) set_currentTab(needItem[0]);
  };

  const getTabs = async () => {
    // const { systemId } = JSON.parse((localStorage.getItem('currentSelectedTab')) as string)
    // const resp = await getDicDataBySysId(systemId, 'PROFIT_REPORT_TYPE');
    const resp = await getUserHasReports();
    if (resp) {
      const { dataVoList } = resp;
      const tempArr = dataVoList.map((a: any) => ({
        label: a.name,
        key: Number(a.code),
        value: a.value,
      }));
      const arr = tempArr.filter((a: any) => a.value != '2');
      set_tabs([...arr]);
      set_currentTabKey(arr[0].key);
      set_currentTab(arr[0]);
    }
  };

  const getResponsibleCenterList = async (reportType: string) => {
    const resp = await getResponsibleCenters(reportType);
    if (resp) {
      set_responsibleCenters(resp);
    }
  };

  const onLeftChange = (currentSelected: any) => {
    set_currentSelectedRespon(currentSelected);
  };

  const tableDataSearchHandle = useCallback(
    (paramName: string) => {
      set_tableDataFilterParams((prev: any) => ({
        ...prev,
        [`${paramName}`]: tableDataSearchKeywords,
      }));
    },
    [tableDataSearchKeywords],
  );

  const onekeyComputeProfitHandle = async () => {
    Modal.confirm({
      title: '注意',
      content: '一键计算操作会覆盖当月已计算的数据，是否继续操作？',
      okText: '确定',
      cancelText: '取消',
      onOk: async () => {
        try {
          const promises = tabs.map((tab) =>
            computeProfitReq(computeDate, tab.key),
          ); // 对每个tab创建一个请求
          const results = await Promise.all(promises); // 等待所有请求完成

          const allSuccess = results.every((resp) => resp); // 检查所有请求是否都成功
          if (allSuccess) {
            message.success('操作成功！');
            set_calcResultText('一键计算成功！');
          } else {
            set_calcResultText('一键计算部分失败！');
          }

          tableRef.current?.reload(); // 重新加载表格数据
        } catch (error) {
          message.error('操作失败，请重试！');
          set_calcResultText('一键计算失败！');
        }
      },
    });
  };

  const computeProfitHandle = async () => {
    Modal.confirm({
      title: '注意',
      content: '计算操作会覆盖当月已计算的数据，是否继续操作？',
      okText: '确定',
      cancelText: '取消',
      onOk: async (...args) => {
        const resp = await computeProfitReq(computeDate, currentTabKey);
        if (resp) {
          message.success('操作成功！');
          set_calcResultText('计算成功！');
          tableRef.current?.reload();
        } else {
          set_calcResultText('计算失败！');
        }
      },
    });
  };

  const openTableDataDrawer = async () => {
    set_drawerTableVisible(true);
    set_loadingtransform(true);
    try {
      if (currentTab?.value == '3') {
        const resp = await getReportDataReq(currentTabKey, computeDate, '3');
        if (resp) {
          await yieldToBrowser();
          const { title = [], data = [] } = resp;
          const defaultColumns: ProColumns[] = [
            {
              title: '报表项目名称',
              dataIndex: 'reportName',
              key: 'reportName',
              width: 220,
              fixed: 'left',
            },
          ];
          const nextTableColumns = generateTableColumns(
            title,
            'responsibilityName',
          );
          const nextDataSource = transformTreeData(data);
          set_tableColumns([...defaultColumns, ...nextTableColumns]);
          set_titleColumnColorMap(
            buildTitleColumnColorMap(title, 'responsibilityName'),
          );
          set_drawerDataSource(nextDataSource);
          set_drawerExpandedKeys(findFirstLevelParentKeys(nextDataSource));
        }
      } else if (currentTab?.value) {
        const resp = await getReportDataReq(
          currentTabKey,
          computeDate,
          currentTab.value,
        );
        if (resp) {
          await yieldToBrowser();
          const { title = [], data = [] } = resp;
          const defaultColumns = [
            {
              title: '科室名称',
              dataIndex: 'responsibilityName',
              key: 'responsibilityName',
              width: 220,
              fixed: 'left',
            },
          ];

          const nextTableColumns = generateTableColumns(title, 'reportName');
          const nextDataSource = processTree(data);
          set_tableColumns([...defaultColumns, ...nextTableColumns]);
          set_titleColumnColorMap(
            buildTitleColumnColorMap(title, 'reportName'),
          );
          set_drawerDataSource(nextDataSource);
          set_drawerExpandedKeys(findFirstLevelParentKeys(nextDataSource));
        }
      }
    } finally {
      set_loadingtransform(false);
    }
  };

  const getHeaderRows = (
    columns: any[],
    level = 0,
    headerRows: any[] = [],
    maxLevel = 0,
  ) => {
    // 规则变更：将叶子列标题统一下沉至最底行（maxLevel - 1），
    // 上方各层以空白占位，避免纵向合并导致“高单元格”。
    headerRows[level] = headerRows[level] || [];
    columns.forEach((col: { title: any; children: any }) => {
      const colSpan = getColSpan(col);
      if (col.children) {
        // 父节点仅进行横向合并，不做纵向合并
        headerRows[level].push({ title: col.title, colSpan, rowSpan: 1 });
        getHeaderRows(col.children, level + 1, headerRows, maxLevel);
      } else {
        // 叶子：从当前层到倒数第二层使用空白占位，叶子标题写入最底层
        for (let i = level; i < maxLevel - 1; i++) {
          headerRows[i] = headerRows[i] || [];
          headerRows[i].push({ title: '', colSpan: 1, rowSpan: 1 });
        }
        headerRows[maxLevel - 1] = headerRows[maxLevel - 1] || [];
        headerRows[maxLevel - 1].push({
          title: col.title,
          colSpan: 1,
          rowSpan: 1,
        });
      }
    });
    return headerRows;
  };

  const getColSpan: any = (col: { children: any[] }) => {
    if (!col.children) return 1;
    return col.children.reduce((sum, child) => sum + getColSpan(child), 0);
  };

  const getMaxLevel = (col: any) => {
    if (!col.children) return 1;
    return 1 + Math.max(...col.children.map(getMaxLevel));
  };

  const extractLeafColumnsWithInheritedColor = (
    columns: any[],
    inheritedColor?: string,
  ) => {
    let leafColumns: Array<{ column: any; color?: string }> = [];
    columns.forEach((col) => {
      const currentColor = getRawReportFontColor(col) || inheritedColor;
      if (col.children && col.children.length > 0) {
        leafColumns = leafColumns.concat(
          extractLeafColumnsWithInheritedColor(col.children, currentColor),
        );
      } else {
        leafColumns.push({ column: col, color: currentColor });
      }
    });
    return leafColumns;
  };

  const addRowWithIndentation = (
    record: any,
    level: number,
    leafColumns: any[],
    worksheetData: any[],
    dataRowColors: Array<string | undefined>,
    renderedRowColorMap: Map<string, string>,
  ) => {
    const row = leafColumns.map((col) => {
      let value = record[col.dataIndex] ?? '';

      // 应用 renderText 函数来格式化导出数据，保持与表格渲染时一致
      if (col.renderText) {
        value = col.renderText(value, record);
      }

      return value;
    });

    // 在第一列前添加缩进空格以表示层级
    row[0] = ' '.repeat(level * 4) + row[0]; // 每一级增加 4 个空格作为缩进

    worksheetData.push(row);
    const rowKey = (record?.id ?? record?.key ?? '') as string | number;
    const renderedRowColor =
      rowKey !== ''
        ? pickMeaningfulColor(renderedRowColorMap.get(String(rowKey)))
        : undefined;
    const explicitRowColor = pickMeaningfulColor(
      convertToExcelRgb(getRawReportFontColor(record)),
    );
    dataRowColors.push(explicitRowColor || renderedRowColor);

    // 递归处理子节点
    if (record.children) {
      record.children.forEach((child: any) =>
        addRowWithIndentation(
          child,
          level + 1,
          leafColumns,
          worksheetData,
          dataRowColors,
          renderedRowColorMap,
        ),
      );
    }
  };

  const handleExport = () => {
    try {
      const workbook = XLSX.utils.book_new();
      const worksheetData: any[] = [];

      // 获取最大层级
      const maxLevel = tableColumns.reduce(
        (max, col) => Math.max(max, getMaxLevel(col)),
        0,
      );

      // 生成多层级表头
      const headerRows = getHeaderRows(tableColumns, 0, [], maxLevel);

      // 构建表头行
      headerRows.forEach((row: any, rowIndex) => {
        const rowData: string[] = [];
        row.forEach(
          (cell: { title: any; colSpan: number; rowSpan: number }) => {
            rowData.push(cell.title);
            for (let i = 1; i < cell.colSpan; i++) {
              rowData.push('');
            }
          },
        );
        worksheetData.push(rowData);
      });

      // 填充单层表头的空白行
      if (maxLevel > 1) {
        const numColumns = headerRows[0].reduce(
          (sum: any, cell: { colSpan: any }) => sum + cell.colSpan,
          0,
        );
        for (let i = 1; i < maxLevel; i++) {
          while (worksheetData[i].length < numColumns) {
            worksheetData[i].push('');
          }
        }
      }

      // 提取最内层表头列，并继承 title 树上的 fontColor（父级颜色可作用到整列）
      const leafColumnsWithColor =
        extractLeafColumnsWithInheritedColor(tableColumns);
      const leafColumns = leafColumnsWithColor.map((item) => item.column);
      const dataRowColors: Array<string | undefined> = [];
      const columnColors: Array<string | undefined> = leafColumnsWithColor.map(
        (item) => {
          const dataIndexKey =
            item?.column?.dataIndex !== undefined
              ? String(item.column.dataIndex)
              : '';
          const titleColor = dataIndexKey
            ? titleColumnColorMap[dataIndexKey]
            : undefined;
          return pickMeaningfulColor(
            convertToExcelRgb(titleColor || item.color),
          );
        },
      );
      const renderedRowColorMap = collectRenderedRowColorMap();

      // 添加数据并处理树结构
      drawerDataSource.forEach((record) =>
        addRowWithIndentation(
          record,
          0,
          leafColumns,
          worksheetData,
          dataRowColors,
          renderedRowColorMap,
        ),
      );

      const worksheet = XLSX.utils.aoa_to_sheet(worksheetData);

      // 初始化合并单元格数组
      worksheet['!merges'] = worksheet['!merges'] || [];

      // 合并单元格
      headerRows.forEach((row: any, rowIndex) => {
        let colIndex = 0;
        row.forEach((cell: { colSpan: number; rowSpan: number }) => {
          if (cell.colSpan > 1 || cell.rowSpan > 1) {
            worksheet['!merges']!.push({
              // 使用非空断言 '!'
              s: { r: rowIndex, c: colIndex },
              e: {
                r: rowIndex + cell.rowSpan - 1,
                c: colIndex + cell.colSpan - 1,
              },
            });
          }
          colIndex += cell.colSpan;
        });
      });

      // 设置单元格对齐方式
      Object.keys(worksheet).forEach((cell) => {
        if (cell[0] !== '!') {
          worksheet[cell].s = {
            alignment: { vertical: 'center', horizontal: 'center' },
          };
        }
      });

      // 表头加粗：对 headerRows 对应的单元格区域（含横向合并范围）统一设置加粗
      headerRows.forEach((row: any, rowIndex: number) => {
        let colIndex = 0;
        row.forEach((cell: { colSpan: number; rowSpan?: number }) => {
          const spanCols = cell.colSpan || 1;
          const spanRows = cell.rowSpan || 1;
          for (let r = rowIndex; r < rowIndex + spanRows; r++) {
            for (let c = colIndex; c < colIndex + spanCols; c++) {
              const cellRef = XLSX.utils.encode_cell({ r, c });
              if (!worksheet[cellRef]) {
                (worksheet as any)[cellRef] = { t: 's', v: '' };
              }
              const prevStyle = (worksheet as any)[cellRef].s || {};
              (worksheet as any)[cellRef].s = {
                ...prevStyle,
                font: {
                  name: '微软雅黑',
                  sz: 11,
                  ...(prevStyle.font || {}),
                  bold: true,
                },
                alignment: prevStyle.alignment || {
                  vertical: 'center',
                  horizontal: 'center',
                },
              };
            }
          }
          colIndex += spanCols;
        });
      });

      // 表头字体颜色：按叶子列的颜色映射到最底层表头（与列颜色保持一致）
      const headerRowsCount = headerRows.length;
      const leafHeaderRowIndex = Math.max(0, headerRowsCount - 1);
      for (let colIndex = 0; colIndex < leafColumns.length; colIndex++) {
        const cellColor = columnColors[colIndex];
        if (!cellColor) continue;
        const excelColor =
          cellColor.length === 6 ? `FF${cellColor}` : cellColor;
        const cellRef = XLSX.utils.encode_cell({
          r: leafHeaderRowIndex,
          c: colIndex,
        });
        if (!worksheet[cellRef]) continue;
        const prevStyle = worksheet[cellRef].s || {};
        worksheet[cellRef].s = {
          ...prevStyle,
          font: {
            name: '微软雅黑',
            sz: 11,
            ...(prevStyle.font || {}),
            bold: true,
            color: { rgb: excelColor },
          },
          alignment: prevStyle.alignment || {
            vertical: 'center',
            horizontal: 'center',
          },
        };
      }

      dataRowColors.forEach((rowColor, index) => {
        const rowIndex = headerRowsCount + index;
        for (let colIndex = 0; colIndex < leafColumns.length; colIndex++) {
          const cellColor = rowColor || columnColors[colIndex];
          if (!cellColor) continue;
          const excelColor =
            cellColor.length === 6 ? `FF${cellColor}` : cellColor;
          const cellRef = XLSX.utils.encode_cell({ r: rowIndex, c: colIndex });
          if (!worksheet[cellRef]) continue;
          const prevStyle = worksheet[cellRef].s || {};
          worksheet[cellRef].s = {
            ...prevStyle,
            font: {
              name: '微软雅黑',
              sz: 11,
              ...(prevStyle.font || {}),
              color: { rgb: excelColor },
            },
            alignment: prevStyle.alignment || {
              vertical: 'center',
              horizontal: 'center',
            },
          };
        }
      });

      XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');

      // 使用 write + saveAs，避免浏览器环境下 writeFile 的样式兼容差异
      const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
      const blob = new Blob([wbout], { type: 'application/octet-stream' });
      saveAs(blob, currentTab ? `${currentTab.label}.xlsx` : 'table_data.xlsx');
    } catch (error) {
      console.error('Export failed:', error);
    }
  };

  const handleExpandNext = useCallback(() => {
    set_allParentsKeys((prev) => {
      const keysToExpand = getNextUnexpandedKeys(
        mainTableDataSource,
        new Set(prev),
      );
      if (keysToExpand.length === 0) return prev;
      return Array.from(new Set([...prev, ...keysToExpand]));
    });
  }, [mainTableDataSource]);

  const handleCollapseAll = useCallback(() => {
    set_allParentsKeys([]);
  }, []);

  const handleMainTableExpand = useCallback(
    (expanded: boolean, record: any) => {
      const { id } = record;
      set_allParentsKeys((prev) => {
        if (!expanded) {
          return prev.filter((key) => key != id);
        }
        if (prev.includes(id)) {
          return prev;
        }
        return [...prev, id];
      });
    },
    [],
  );

  const mainTableRowClassName = useCallback(
    (record: any) =>
      `${
        record.children ? 'has-children ' : ''
      }hover-row report-font-color-row`,
    [],
  );

  const drawerTableRowClassName = useCallback(
    (record: any) =>
      `${record.children ? 'has-children ' : ''}report-font-color-row`,
    [],
  );

  const emptyRowProps = useMemo(() => ({}), []);

  const getReportRowProps = useCallback(
    (record: any) => {
      const color = getRawReportFontColor(record);
      if (!color) return emptyRowProps;
      return {
        style: {
          ['--report-font-color' as any]: color,
        } as React.CSSProperties,
      };
    },
    [emptyRowProps],
  );

  const handleDrawerExpand = useCallback((expanded: boolean, record: any) => {
    const { id } = record;
    set_drawerExpandedKeys((prev) => {
      if (!expanded) {
        return prev.filter((key) => key != id);
      }
      if (prev.includes(id)) {
        return prev;
      }
      return [...prev, id];
    });
  }, []);

  useEffect(() => {
    if (computeDate && currentTabKey != undefined) {
      getResponsibleCenterList(currentTabKey);
    }
    set_allParentsKeys([]);
    set_mainTableDataSource([]);
    set_drawerDataSource([]);
    set_drawerExpandedKeys([]);
  }, [computeDate, currentTabKey]);

  useEffect(() => {
    if (currentSelectedRespon) {
      set_tableDataFilterParams((prev: any) => ({
        ...prev,
        responsibilityCode: currentSelectedRespon.responsibilityCode,
        reportType: currentTabKey,
        computeDate: computeDate,
      }));
    }
    set_allParentsKeys([]);
    set_mainTableDataSource([]);
    set_drawerDataSource([]);
    set_drawerExpandedKeys([]);
  }, [computeDate, currentSelectedRespon, currentTabKey]);

  useEffect(() => {
    getTabs();
    getIfshowPercent();
  }, []);

  const drawerTableScroll = useMemo(() => {
    return {
      x: countLeafNodes(tableColumns) * 200,
      y: `calc(100vh - ${
        84 +
        tableColumns.reduce((max, col) => Math.max(max, getMaxLevel(col)), 0) *
          38
      }px)`,
    };
  }, [tableColumns]);

  return (
    <KCIMPagecontainer className="DepartmentCostCalc" title={false}>
      <Drawer
        className="drawerTable"
        contentWrapperStyle={{}}
        bodyStyle={{ padding: 16 }}
        title={false}
        open={drawerTableVisible}
        width={1000}
        headerStyle={{ display: 'none' }}
      >
        <div className="header">
          <div className="title">
            {currentTab ? currentTab.label : ''}（单位：元）
          </div>

          <div className="btns">
            <span onClick={() => set_drawerTableVisible(false)}>关闭</span>
            <span className="close" onClick={() => handleExport()}>
              导出
            </span>
          </div>
        </div>
        {/* {loadingtransform && <Skeleton />} */}
        <KCIMTable
          loading={loadingtransform}
          expandable={{
            defaultExpandedRowKeys: drawerExpandedKeys,
          }}
          components={drawerVirtualComponents}
          className="departmentCostCalcReportTable"
          key={drawerDataSource.length ? 'loaded' : 'empty'}
          dataSource={drawerDataSource}
          bordered
          pagination={false}
          rowClassName={drawerTableRowClassName}
          onRow={getReportRowProps}
          scroll={drawerTableScroll}
          columns={tableColumns as ProColumns[]}
          rowKey="id"
        />
      </Drawer>

      <div className="header">
        <div className="search">
          <span>核算年月：</span>
          <DatePicker
            onChange={(data, dateString) => {
              set_computeDate(dateString);
              setInitialState((s: any) => ({ ...s, computeDate: dateString }));
              set_tableDataFilterParams((prev: any) => ({
                ...prev,
                computeDate: dateString,
              }));
            }}
            picker="month"
            locale={locale}
            defaultValue={moment(computeDate, 'YYYY-MM')}
            format="YYYY-MM"
            autoComplete="off"
            placeholder="选择年月"
          />
        </div>
        <div className="btnGoup">
          <span
            className="onekeyCalcBtn"
            onClick={() => onekeyComputeProfitHandle()}
          >
            一键计算
          </span>
        </div>
      </div>
      <div className="content">
        <Tabs
          defaultActiveKey={tabs.length > 0 ? tabs[0].key : undefined}
          items={tabs}
          key={'key'}
          onChange={(key) => onTabChanged(key)}
        />
        {calcResultText && (
          <Alert
            showIcon
            onClose={() => set_calcResultText(undefined)}
            icon={
              <IconFont
                type={
                  calcResultText.indexOf('失败') != -1
                    ? 'icon-cuowutishi'
                    : 'icon-chenggongtishi'
                }
              />
            }
            closable
            style={{
              padding: '4px 12px',
              marginBottom: 16,
              borderRadius: 4,
              border:
                calcResultText.indexOf('失败') != -1 ? '1px solid #73E6BF' : '',
              background:
                calcResultText.indexOf('失败') != -1 ? '#FFF1F3' : '#EBFFF8',
            }}
            message={calcResultText}
            type={calcResultText.indexOf('失败') != -1 ? 'error' : 'success'}
          />
        )}
        <div className="inner">
          <div className="left">
            <KCIMLeftList
              fieldNames={{
                title: 'responsibilityName',
                key: 'responsibilityCode',
                children: 'children',
              }}
              rowKey={'responsibilityCode'}
              dataSource={responsibleCenters}
              searchKey={'responsibilityName'}
              onChange={onLeftChange}
              contentH={`100%`}
              // placeholder={leftListSearchPlaceHolder}
              listType={'tree'}
            />
          </div>
          <div className="right">
            <div className="toolBar">
              <div className="filterItem" style={{ width: 228 }}>
                <span className="label" style={{ whiteSpace: 'nowrap' }}>
                  {' '}
                  检索：
                </span>
                <Input
                  placeholder={'报表项目代码/名称'}
                  allowClear
                  autoComplete="off"
                  suffix={
                    <IconFont
                      type="iconsousuo"
                      style={{ color: '#99A6BF' }}
                      onClick={() => tableDataSearchHandle('filter')}
                    />
                  }
                  onChange={(e) => {
                    set_tableDataSearchKeywords(e.target.value);
                    if (e.target.value.length == 0) {
                      set_tableDataFilterParams((prev: any) => ({
                        ...prev,
                        filter: '',
                      }));
                    }
                  }}
                  onPressEnter={(e) => {
                    set_tableDataFilterParams((prev: any) => ({
                      ...prev,
                      filter: (e.target as HTMLInputElement).value,
                    }));
                  }}
                />
              </div>
              <div className="btnGroup">
                <span className="btn" onClick={() => handleCollapseAll()}>
                  全部折叠
                </span>
                <span
                  className="btn"
                  style={{ marginRight: 16 }}
                  onClick={() => handleExpandNext()}
                >
                  展开下一层
                </span>
                <span className="btn" onClick={() => openTableDataDrawer()}>
                  报表数据
                </span>
                <span className="calc" onClick={() => computeProfitHandle()}>
                  计算
                </span>
              </div>
            </div>
            <KCIMTable
              pagination={false}
              rowClassName={mainTableRowClassName}
              onRow={getReportRowProps}
              expandable={{
                expandedRowKeys: allParentsKeys,
                onExpand: handleMainTableExpand,
              }}
              columns={columns as ProColumns[]}
              scroll={{ y: `calc(100vh - 302px)` }}
              actionRef={tableRef}
              rowKey="id"
              params={tableDataFilterParams}
              request={(params) => getTableData(params)}
            />
          </div>
        </div>
      </div>
    </KCIMPagecontainer>
  );
}
