<?php
namespace model\pdflib;

use app\tech;
use model;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use lib\image;
use model\import\itemLink;

define('THIS_DEBUG', false);

define('PT_SALC', 0.75);
define('CM_SALC', 37.795275591);
define('MODELS_REMARK_COL_JG', 'K');
define('MODELS_REMARK_COL', 'L');
define('SCALING_FACTOR', 1 / 0.92); // 目标比例是 Excel 会缩放到 92% //1.023
define('HEAER_IMAGE_FD', 1.5);
define('DEFAULT_ROW_HEIGHT', 14.25); //默认行高
define('MAX_PAGE_HEIGHT', 911.625); //最大页高

class pdfSS extends model {
    public $dataVer = "'Y1','Y2','Y4'";
    public $number_ckresult2 = "10121";
    public $cates = "";
    public $image = null; //图片处理类
    public $transparentPng = ''; //透明图片
    public $tmpDir = '';
    public $staticDir = '';
    public $modelHeader = [];
    public $remarkSeq = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨'];
    public $A4Height = 842; //A4页高
    public $rowNum = 1;
    public $activeLineHeight = 0; //当前图片高
    public $activePageStartRow = 1; //当前分页开始行
    public $activeImageRow = 0; //当前图片行
    public $activeImageEmptyRow = 0;//当前图片最后一个空行
    public $pagesHeight = []; //各分页高度
    public $cellColors = [];
    public $pageRows = []; //已经计算过页高的行数
    public $isSetHeightRows = []; //已设置过的行高
    public function __construct($cateid)
    {
        parent::__construct();
        $row = $this->db->get('pdf_cate','*',['pdfc_id' => $cateid]);
        $this->cates = $row['pdfc_cates'];
        $this->image = new image();
        $this->staticDir = \mvc::$cfg['dir']['static'] . '/images/pdf/ss';
        $this->transparentPng = $this->staticDir . '/transparent.png';
        $this->tmpDir = \mvc::$cfg['dir']['cache'] . '/tmp_pdf_ss';
        mkdirs($this->tmpDir);
        $this->modelHeader = [
            1 => [
                'filename' => $this->staticDir . '/1.png',
                'width' => 820 * SCALING_FACTOR,
                'height' => 61,
            ],
            2 => [
                'filename' => $this->staticDir . '/2.png',
                'width' => 820 * SCALING_FACTOR,
                'height' => 97,
            ],
            4 => [
                'filename' => $this->staticDir . '/4.png',
                'width' => 820 * SCALING_FACTOR,
                'height' => 96,
            ],
            6 => [
                'filename' => $this->staticDir . '/6.png',
                'width' => 820 * SCALING_FACTOR,
                'height' => 94,
            ],
            9 => [
                'filename' => $this->staticDir . '/9.png',
                'width' => 820 * SCALING_FACTOR,
                'height' => 129,
            ],
        ];
    }
    //数字转字母列
    protected function int2Excel($num)
    {
        $num -= 1;
        $az = 26;
        $m = (int)($num % $az);
        $q = (int)($num / $az);
        $letter = chr(ord('A') + $m);
        if ($q > 0) {
            return int2Excel($q - 1) . $letter;
        }
        return $letter;
    }

    public function getPos($row)
    {
        $ssc_pos = $row['ss_pos'];
        $row['pos1'] = ''; //前后轴
        $row['pos2'] = ''; //左右
        $row['pos3'] = ''; //外中内
        $row['pos4'] = ''; //上中下
        $arr = explode(' ', $ssc_pos);
        if (stripos($ssc_pos, 'Front Axle') !== false) {
            $row['pos1'] = 'F';
        }
        if (stripos($ssc_pos, 'Rear Axle') !== false) {
            $row['pos1'] = 'R';
        }

        if (stripos($ssc_pos, 'Left') !== false) {
            $row['pos2'] = 'L';
        }
        if (stripos($ssc_pos, 'Right') !== false) {
            $row['pos2'] = 'R';
        }
        if (stripos($ssc_pos, 'Left And Right') !== false) {
            $row['pos2'] = 'L/R';
        }

        if (stripos($ssc_pos, 'Outer') !== false) {
            $row['pos3'] = 'O';
        }
        if (stripos($ssc_pos, 'Inner') !== false) {
            $row['pos3'] = 'I';
        }
        if ($arr[count($arr) - 2] == 'Center' || $arr[count($arr) - 2] == 'Centre') {
            $row['pos3'] = 'C';
        }

        if (stripos($ssc_pos, 'Low') !== false) {
            $row['pos4'] = 'L';
        }
        if (stripos($ssc_pos, 'Upper') !== false) {
            $row['pos4'] = 'U';
        }
        if ($arr[count($arr) - 1] == 'Center' || $arr[count($arr) - 1] == 'Centre') {
            $row['pos4'] = 'C';
        }
        return $row;
    }

    protected function sortItems($array)
    {
        $ssNameOrder = array_map('strtolower', [
            'Steering Rack Bellow Kit',
            'Steering Boot',
            'Tie Rod End',
            'Tie Rod Axle Joint',
            'Rod Assembly',
            'Drag Link',
            'Pitman Arm',
            'Idler Arm',
            'Ball Joint',//
            'Control Arm',
            'Track Control Arm',
            'Control Arm Bush',
            'Control Arm Bushing',
            'Control Arm Bush Kit',
            'Control Arm Bushing Kit',
            //'Ball Joint',
            'Suspension Repair Kit',
            'Rod/Strut,stabiliser',
            'Stabiliser Bushing',
            'Stabiliser Bushing Kit'
        ]);

        $pos1Order = ['', 'F', 'R']; 
        $pos4Order = ['U', 'C', 'L', ''];
        $pos3Order = ['', 'I', 'C', 'O'];
        $pos2Order = ['', 'L/R', 'L', 'R'];

        usort($array, function ($a, $b) use ($ssNameOrder, $pos1Order, $pos2Order, $pos4Order, $pos3Order) {
            // 1. 第一优先级：按pos1排序
            $aPos1Index = array_search($a['pos1'], $pos1Order);
            $bPos1Index = array_search($b['pos1'], $pos1Order);
            if ($aPos1Index !== $bPos1Index) {
                if ($aPos1Index === false) return 1;
                if ($bPos1Index === false) return -1;
                return $aPos1Index - $bPos1Index;
            }

            // 2. 第二优先级：按ss_name排序
            $aNameIndex = array_search(strtolower($a['ss_name']), $ssNameOrder);
            $bNameIndex = array_search(strtolower($b['ss_name']), $ssNameOrder);
            if ($aNameIndex !== $bNameIndex) {
                if ($aNameIndex === false) return 1;
                if ($bNameIndex === false) return -1;
                return $aNameIndex - $bNameIndex;
            }

            // 3. 其他条件
            foreach (
                [
                    ['key' => 'pos4', 'order' => $pos4Order],
                    ['key' => 'pos3', 'order' => $pos3Order],
                    ['key' => 'pos2', 'order' => $pos2Order],
                ] as $rule
            ) {
                $aIndex = array_search($a[$rule['key']], $rule['order']);
                $bIndex = array_search($b[$rule['key']], $rule['order']);
                if ($aIndex !== $bIndex) {
                    if ($aIndex === false) return 1;
                    if ($bIndex === false) return -1;
                    return $aIndex - $bIndex;
                }
            }

            // 4. 最后按ss_remark日期排序
            $aDate = preg_match('/Date from:(\d{4}\.\d{2})/', $a['ss_remark'], $aMatches) ? $aMatches[1] : null;
            $bDate = preg_match('/Date from:(\d{4}\.\d{2})/', $b['ss_remark'], $bMatches) ? $bMatches[1] : null;

            if ($aDate !== null && $bDate !== null) {
                return strcmp($aDate, $bDate);
            }
            if ($aDate !== null) return -1;
            if ($bDate !== null) return 1;

            return 0;
        });
        return $array;
    }

    public function mergeRemarksWithSymbols($remarks)
    {
        $valueMap = [];

        // 创建值到索引的映射，并过滤掉内容为空的项
        foreach ($remarks as $index => $value) {
            $trimmed = trim((string)$value);
            if ($trimmed === '') {
                continue; // 跳过空内容
            }

            if (!isset($valueMap[$trimmed])) {
                $valueMap[$trimmed] = [];
            }
            $valueMap[$trimmed][] = $index;
        }

        // 数字到符号的映射
        $symbols = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];

        $result = [];

        foreach ($valueMap as $value => $indexes) {
            // 将数字索引转换为符号
            $symbolIndexes = array_map(function ($index) use ($symbols) {
                return $symbols[$index] ?? (string)($index + 1);
            }, $indexes);

            if (count($symbolIndexes) > 1) {
                $mergedSymbols = implode('/', $symbolIndexes);
                $result[] = "$mergedSymbols: $value";
            } else {
                $result[] = "{$symbolIndexes[0]}: $value";
            }
        }

        // 按原始顺序排序（基于第一个出现的索引）
        usort($result, function ($a, $b) {
            preg_match('/^([①-⑩]+)/u', $a, $matchesA);
            preg_match('/^([①-⑩]+)/u', $b, $matchesB);

            // 将符号转换回数字比较
            $symbolToNum = function ($symbol) {
                $symbols = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];
                $pos = array_search($symbol[0], $symbols);
                return $pos !== false ? $pos : (int)$symbol;
            };

            $aNum = $symbolToNum($matchesA[1][0]);
            $bNum = $symbolToNum($matchesB[1][0]);

            return $aNum - $bNum;
        });

        return $result;
    }


    //导出相同GSP型号的小车型列表
    public function exportSameModelGspNo()
    {
        $sql = "SELECT p_id,p_cate,ss.*,CONCAT(ssc_model, ' ', ss_year_range) model,ppic_filebase
        ,files.filename,fileextname from catalog_ss ss
JOIN pro ON p_outnum = ss.ssc_outnum
LEFT OUTER JOIN pro_pic pic ON ppic_p_id = p_id AND ppic_type IN ('beautify','beautify_replay') AND  ppic_innum like ppic_filebase
LEFT OUTER JOIN files ON fileid = ppic_fileid
WHERE
!EXISTS(SELECT 1 FROM catalog_ss_ignore WHERE ssc_make=cssi_make AND  ssc_model=cssi_model AND ssc_outnum = cssi_outnum)
GROUP BY ssc_make,model,p_id
ORDER BY ssc_make, model,ssc_outnum,ss_remark
";
        $rows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
        $data = [];
        $modelOutnums = [];
        foreach ($rows as $i => $row) {
            $model = $row['model'];
            $row = $this->getPos($row);
            $data[$row['ssc_make']][$model][] = $row;
            $modelOutnums[$row['ssc_make']][$model][] = trim($row['ssc_outnum']);
        }
        //分析构建:相同gsp型号的小车型数组
        $sameOutnums = [];
        foreach ($modelOutnums as $make => $models) {
            foreach ($models as $model => $outnums) {
                sort($outnums);
                $md5 = md5(json_encode($outnums));
                $sameOutnums[$make][$md5][] = $model;
            }
        }
        // 找出备注不同的(在相同gsp型号的小车型条件下)
        $diffRemarks = [];
        foreach ($sameOutnums as $make => $group) {
           foreach ($group as $gk => $models) {
                if(count($models) >1) {
                    $remarks = [];
                    $hasDiff = false;
                    foreach ($models as $i => $model) {
                        $items = $data[$make][$model];
                        foreach ($items as $item) {
                            if (isset($remarks[$make][$gk][$item['ssc_outnum']])) {
                                if (!in_array($item['ss_remark'], $remarks[$make][$gk][$item['ssc_outnum']]['remarks'])) {
                                    $remarks[$make][$gk][$item['ssc_outnum']]['diff'] = true;
                                    $hasDiff = true;
                                }
                            }
                            $remarks[$make][$gk][$item['ssc_outnum']]['remarks'][$i] = $item['ss_remark'] ?: '';
                        }
                    }
                    if ($hasDiff) {
                        foreach ($remarks as $rMake => $rGroup) {
                            foreach ($rGroup as $rGk => $outnumItems) {
                                foreach ($outnumItems as $outnum => $outnumItem) {
                                    if ($outnumItem['diff']){
                                        $outnumItem['remarksChange'] = $this->mergeRemarksWithSymbols($outnumItem['remarks']);
                                        $outnumItem['remarksChange'] = implode("<br>\n", $outnumItem['remarksChange']);
                                    } else {
                                        $outnumItem['remarksChange'] = $outnumItem['remarks'][0];
                                    }
                                    $outnumItems[$outnum] = $outnumItem;
                                }
                                $rGroup[$rGk] = $outnumItems;
                            }
                            $remarks[$rMake] = $rGroup;
                        }
                        $diffRemarks[$make][$gk] = $remarks[$make][$gk];
                    }
                }
           }
        }
        return [$sameOutnums, $diffRemarks];
    }


    public function getData($makeModels)
    {
        $makes = array_column($makeModels, 'make');
        $makes = array_unique($makes);

        $models = array_column($makeModels, 'model');
        $models = array_unique($models);

        $inMakesText = "'" . implode("','", $makes) . "'";
        $inModelsText = "'" . implode("','", $models) . "'";

        $sql = "SELECT p_id,p_cate,ss.*,CONCAT(ssc_model, ' ', ss_year_range) model,ppic_filebase
        ,files.filename,fileextname from catalog_ss ss
JOIN pro ON p_outnum = ss.ssc_outnum
LEFT OUTER JOIN pro_pic pic ON ppic_p_id = p_id AND ppic_type IN ('beautify','beautify_replay') AND  ppic_innum like ppic_filebase
LEFT OUTER JOIN files ON fileid = ppic_fileid
WHERE
ssc_make IN (" . $inMakesText . ")
AND ssc_model IN (" . $inModelsText . ")
AND !EXISTS(SELECT 1 FROM catalog_ss_ignore WHERE ssc_make=cssi_make AND  ssc_model=cssi_model AND ssc_outnum = cssi_outnum)
GROUP BY ssc_make,model,p_id
ORDER BY ssc_make, model,
ssc_outnum,
FIELD(ppic_type, 'beautify','beautify_replay'),
ss_remark
";
        //dd($sql);
        $rows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);      
        $data = [];
        foreach ($rows as $i => $row) {
            $model = $row['model'];
            $row = $this->getPos($row);
            $data[$row['ssc_make']][$model][] = $row;
        }
        // 大车型相同，gsp no 相同, 小车型不同的合并在一起
        $newData = [];
        foreach ($data as $make => $models) {
            foreach ($models as $model => $items) {
                $uid = '';
                $mergeModels =  [];
                foreach ($items as $item) {
                    $uid .= trim($item['ssc_make']) . '-' . trim($item['ssc_outnum']);// . '-' . $item['ss_remark'];
                    $mergeModels[] = $item['model'];
                }
                $mergeModels = array_unique($mergeModels);
                $key = md5($uid);
                if (!isset($newData[$make][$key])) {
                    $newData[$make][$key] = [
                        'models' => [],
                        'items' => [],
                    ];
                }
                $newData[$make][$key]['items'] = $items;
                $newData[$make][$key]['models'] = array_merge($newData[$make][$key]['models'], $mergeModels);
            }
        }
        //dd($newData);
        $data = $newData;
        unset($newData);
        // 多个小车型合并，要固定取其中一个小车型的OE
        foreach ($data as $make => $list) {
            foreach ($list as $key => $value) {
                $models = $value['models'];
                if (count($models) > 1) {
                    $firstModel = str_replace("'", "\'", $models[0]);
                    foreach ($value['items'] as $i => $item) {
                        $findSQL = "SELECT ssc_oe FROM catalog_ss WHERE ssc_outnum='" . $item['ssc_outnum'] . "' 
                                    AND CONCAT(ssc_model, ' ', ss_year_range) = '" . $firstModel . "'";
                        $findOE = $this->db->query($findSQL)->fetchColumn();
                        $data[$make][$key]['items'][$i]['ssc_oe'] = $findOE;
                    }
                }
            }
        }
        //        
        foreach ($data as $make => $list) {
            foreach ($list as $key => $value) {
                $models = $value['models'];
                $count = count($models);
                $headers = [];
                if ($count == 1) {
                    $headers[] = 1;
                } elseif ($count == 2) {
                    $headers[] = 2;
                } elseif ($count > 2 && $count < 5) {
                    $headers[] = 4;
                } elseif ($count > 4 && $count < 7) {
                    $headers[] = 6;
                } elseif ($count > 6) {
                    $headers[] = 9;
                }
                $data[$make][$key]['headers'] = $headers;
                $data[$make][$key]['items'] = $this->sortItems($data[$make][$key]['items']);
            }
        }
        list($sameOutnums, $diffRemarks) = $this->exportSameModelGspNo();
        $this->sameOutnums = $sameOutnums;
        $this->diffRemarks = $diffRemarks;
        //dd($sameOutnums,$data);
        return $data;        
    }

    public function hasMoreRemark($make, $model)
    {
        $result =false ;
        if (!isset($this->sameOutnums[$make])) {
            return $result;
        }
        foreach ($this->sameOutnums[$make] as $gk => $models) {
            if (in_array($model, $models) && isset($this->diffRemarks[$make][$gk])) {
                $result = true;
            }
        }
        return $result;
    }

    public function findMoreRemark($make, $model, $outnum)
    {
        $result = '';
        if (!isset($this->sameOutnums[$make])) {
            return '';
        }
        foreach ($this->sameOutnums[$make] as $gk => $models) {
            if (in_array($model, $models) && isset($this->diffRemarks[$make][$gk])) {
                $finditem = $this->diffRemarks[$make][$gk][$outnum];
                if ($finditem['diff']) {
                    $result = str_replace('<br>', '', $finditem['remarksChange']);
                }
            }
        }
        return $result;
    }
    public function cmToInch($cm)
    {
        return $cm / 2.54;
    }

    public function pxToInch($px, $dpi = 96)
    {
        return $px / $dpi;
    }

    public function createExcel($regI, $makeModels) {
        $this->rowNum = 1;
        $this->activeLineHeight = 0; //当前图片高
        $this->activePageStartRow = 1; //当前分页开始行
        $this->activeImageRow = 0; //当前图片行
        $this->activeImageEmptyRow = 0; 
        $this->pagesHeight = []; //各分页高度
        $this->cellColors = [];
        $this->pageRows = []; //已经计算过页高的行数
        $this->isSetHeightRows = []; //已设置过的行高

        $arr = [];
        foreach ($makeModels as $key => $v) {
            if (empty($v)) {
                unset($v[$key]);
            } else {
                list($make,$model) = explode('<->', $v);
                $make = str_replace("'", "\'", $make);
                $model = str_replace("'", "\'", $model);
                $arr[] = ['make' => $make, 'model' => $model];
            }
        }
        $data = $this->getData($arr);

        $sheetIndex = 0;
        $spreadsheet = new Spreadsheet();
        $workSheet = new Worksheet($spreadsheet, 'Sheet' . ($sheetIndex + 1));
        $spreadsheet->getDefaultStyle()->getFont()->setName('Arial')->setSize(11); //Arial,Calibri
        $sheet = $spreadsheet->getActiveSheet();

        $sheet->getPageSetup()
            ->setOrientation(PageSetup::ORIENTATION_PORTRAIT) //纵向
            ->setPaperSize(PageSetup::PAPERSIZE_A4); //A4
        $sheet->getPageSetup()
            ->setFitToPage(true)
            ->setFitToWidth(1)
            ->setFitToHeight(0);
        // 设置页边距（单位：英寸）
        $sheet->getPageMargins()->setTop($this->cmToInch(0.5));       // 上边距
        $sheet->getPageMargins()->setBottom($this->cmToInch(0.5));    // 下边距
        $sheet->getPageMargins()->setLeft($this->cmToInch(0.3));      // 左边距
        $sheet->getPageMargins()->setRight($this->cmToInch(0.3));     // 右边距
        $sheet->getPageMargins()->setHeader($this->cmToInch(1.27));    // 页眉高度
        $sheet->getPageMargins()->setFooter($this->cmToInch(1.27));    // 页脚高度

        $this->A4Height = $this->A4Height - (
            $sheet->getPageMargins()->getTop() +
            $sheet->getPageMargins()->getBottom() +
            $sheet->getPageMargins()->getHeader() +
            $sheet->getPageMargins()->getFooter()
        ) * 28.3465;
        $this->A4Height = $this->A4Height - 0.49;
        $sheet->getDefaultRowDimension()->setRowHeight(DEFAULT_ROW_HEIGHT); //设置默认行高

        //设置列宽
        $columnWidth = 10.30;  //列宽 9.68 (10.39), 11.7
        foreach (range('A', 'J') as $col) {
            $sheet->getColumnDimension($col)->setWidth($columnWidth);
        }
        $sheet->getColumnDimension(MODELS_REMARK_COL_JG)->setWidth(8);
        $sheet->getColumnDimension(MODELS_REMARK_COL)->setWidth(50);
        //$sheet->getStyle(MODELS_REMARK_COL.':'. MODELS_REMARK_COL)->getFont()->setSize(11);
        $sheet->getColumnDimension(MODELS_REMARK_COL)->setAutoSize(true);
        $sheet->getColumnDimension('M')->setWidth(50);

        $this->rowNum = 1;
        foreach ($data as $make => $list) {
            foreach ($list as $key => $group) {
                foreach ($group['headers'] as $headerTag) {
                    $headerData = [];
                    $headerData['make'] = $make;
                    for ($i = 0; $i < count($group['models']); $i++) {
                        $headerData['models'][] = $group['models'][$i];
                    }
                    /*
                    switch ($headerTag) {
                        case 1:
                            $this->insertModelHeader1($sheet, 1, $this->rowNum, $headerData);
                            break;
                        case 2:
                            $this->insertModelHeader2($sheet, 1, $this->rowNum, $headerData);
                            break;
                        case 4:
                            $this->insertModelHeader4($sheet, 1, $this->rowNum, $headerData);
                            break;
                        case 6:
                            $this->insertModelHeader6($sheet, 1, $this->rowNum, $headerData);
                            break;
                        case 9:
                            $this->insertModelHeader9($sheet, 1, $this->rowNum, $headerData);
                            break;
                    }
                    */
                    /*
                    $headerTag = 9;
                    $headerData['models'] = [
                        'aaa',
                        'bbb',
                        'ccc',
                        'ddd',
                        'eee',
                        'FFF',
                        'HHH',
                        'III',
                        'JJJ',
                    ];*/
                    $this->insertModelHeaderAll($headerTag, $sheet, 1, $this->rowNum, $headerData);
                    $this->insertItems($sheet, $group['items']);
                }
                //break;
            }
        }
        $highestRow = $sheet->getHighestRow();
        $sheet->getPageSetup()->setPrintArea("A1:J{$highestRow}");
        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        $filename = $this->tmpDir . '/' . (str_pad($regI, 3, '0', STR_PAD_LEFT)) . '.xlsx'; 
        if (is_file($filename)) @unlink($filename);
        $writer->save($filename); 
        /*
        // 设置文件名
        $filename = 'export_' . date('YmdHis') . '.xlsx';
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '"');
        header('Cache-Control: max-age=0');
        header('Cache-Control: max-age=1');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
        header('Cache-Control: cache, must-revalidate');
        header('Pragma: public');
        $writer->save('php://output');*/
        return $filename;
    }
    public function getPages()
    {
        //按make,model分页 500条
        $sql = "SELECT ssc_make make,ssc_model model,COUNT(*) cnt FROM catalog_ss GROUP BY ssc_make, ssc_model ORDER BY ssc_make, ssc_model";
        $rows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
        $pages = [];
        $current_page = [];
        $current_total = 0;

        foreach ($rows as $row) {
            $key = $row['make'] . '<->' . $row['model'];

            if ($current_total + $row['cnt'] > 500) {
                if ($current_total + $row['cnt'] > 500) {
                    //相同gspno的车型不断页
                    foreach ($sameOutnums as $make => $list) {
                        if ($make == $row['make']) {
                            foreach ($list as $tuid => $items) {
                                if (in_array($row['model'], $items)) {
                                    foreach ($items as $model) {
                                        $tkey = $make . '<->' . $model;
                                        $current_page[] = $tkey;
                                        $skipKeys[] = $tkey;
                                        dd($skipKeys);
                                    }
                                }
                            }
                        }
                    }
                    //
                    $current_page = array_unique($current_page);
                    $pages[] = $current_page;
                    $current_page = [];
                    $current_total = 0;
                }
                $pages[] = $current_page;
                $current_page = [];
                $current_total = 0;
            }

            $current_page[] = $key;
            $current_total += $row['cnt'];
        }

        if (!empty($current_page)) {
            $pages[] = $current_page;
        }
        return $pages;
    }
    public function execute()
    {
        set_time_limit(3600 * 10);
        ini_set('memory_limit', \mvc::$cfg['export_memory_limit']);
        ignore_user_abort(true);
        $pages = $this->getPages();
        $files = [];
        $context = "";
        $listFilename = $this->tmpDir . '/list.txt';
        try {
            foreach ($pages as $k => $makeModels) {
                $filename = $this->createExcel($k, $makeModels);
                $files[$k] = $filename;
                $context .= basename($filename) . "\n" . implode(', ', $makeModels) . "\n\n";
                /*
                if (getOpUser() == 'test.admin') {
                    ob_end_clean();
                    header('Content-Description: File Transfer');
                    header("Content-type:application/vnd.ms-excel");
                    header('Content-Disposition: attachment; filename=' . basename($filename));
                    header("Content-Length:" . filesize($filename));
                    error_reporting(0);
                    readfile($filename);
                    ob_end_flush();
                    exit();
                }*/
            }

            file_put_contents($listFilename, $context);

            $zipfile = $this->tmpDir . "/SS-". getOpuser() . '-' . date('Y-m-d-His') .".zip";
            $zip = new \ZipArchive();
            if ($zip->open($zipfile, \ZIPARCHIVE::CREATE) !== true) {
                throw new \Exception('生成压缩文件'. $zipfile.'失败,请检查相关目录权限');
            }
            $zip->addfile($listFilename, 'list.txt');
            foreach ($files as $key => $filename) {
                $zip->addfile($filename, basename($filename));
            }
            $zip->close();
            $pdffileUrl = \mvc::$cfg['path']['cache'] . '/tmp_pdf_ss/' . basename($zipfile);
            echo '<a href="' . $pdffileUrl . '"> 悬挂电子目录 </a>';
            $msg = [
                'amsg_type' => '0',
                'amsg_title' => '生成悬挂电子目录',
                'amsg_body' => '生成悬挂电子目录完成',
                'amsg_url' => $pdffileUrl,
                'amsg_urltitle' => basename($pdffileUrl),
                'amsg_file' => $zipfile,
            ];
            $message = new \model\message();
            $message->send([getOpuser()], $msg);
            socketSendMsg([getOpuser()], $msg);
            /*
            ob_end_clean();
            header('Content-Description: File Transfer');
            header("Content-type:application/vnd.ms-excel");
            header('Content-Disposition: attachment; filename=' . basename($zipfile));
            header("Content-Length:" . filesize($zipfile));
            error_reporting(0);
            readfile($zipfile);
            ob_end_flush();*/

        } finally {
            //@unlink($zipfile);
            @unlink($listFilename);
            foreach ($files as $filename) {
                @unlink($filename);
            }
        }
        exit();
    }
    public function insertItems($sheet, $items)
    {
        $insertFront = false;
        $insertRear = false;
        $HasInsertPart0 = false; //是否有 转向系之前的数据
        $insertPart1 = false; //是否插入完了 转向系
        $skips = [];
        foreach ($items as $k => $item) {
            /*
            $imgFile = $this->staticDir . '/test/' . $item['ssc_outnum'] . '.png';
            if (!file_exists($imgFile)) {
                $imgFile = $this->staticDir . '/test/' . $item['ssc_outnum'] . '.jpg';
            }
            */
            //正式环境
            $imgFile = \mvc::$cfg['dir']['files'] . '/' . substr($item['filename'], 0, strrpos($item['filename'], '.')) . '.' . $item['fileextname'];
            if (!file_exists($imgFile)) {
                //测试环境
                $imgFile = $this->staticDir . '/test/' . $item['ssc_outnum'] . '.png';
            }
            if (is_file($imgFile)) {
                $tmpFilename = $this->tmpDir . '/' . md5($imgFile) . '.png';
                if (!file_exists($tmpFilename)) {
                    $imgFile = $this->image->Cut2($imgFile, $tmpFilename, 400, 400);
                }
                $items[$k]['imgFile'] = $tmpFilename;
                $items[$k]['noimgFile'] = false;
            } else {
                //unset($items[$k]);
                $items[$k]['noimgFile'] = true;
            }
            $items[$k]['ss_name'] = trim($items[$k]['ss_name']);
        }
        $outnums = array_unique(array_column($items, 'ssc_outnum'));
        foreach ($items as $k => $item) {
            $maxInsertRowsCount = 0;
            $currentKey = $k;
            if (in_array($currentKey, $skips)) {
                continue;
            }
            $name = $item['ss_name'];
            if ($item['pos1'] == 'F' && !$insertFront) {
                $insertFront = true;
                $this->insertFrontAxle($sheet, 1, $this->rowNum);
            }
            if ($item['pos1'] == 'R' && !$insertRear) {
                $insertRear = true;
                if ($insertFront) {
                    $this->insertJgAxle($sheet, 1, $this->rowNum);
                    $this->insertRearAxle($sheet, 1, $this->rowNum);
                } else {
                    $this->insertRearAxle($sheet, 1, $this->rowNum, 'noJg');
                }
            }
            $startRow = $this->rowNum;

            //转向机防尘罩修理包
            if ($name == 'Steering Rack Bellow Kit') {
                include(__DIR__ . '/ss/SteeringRackBellowKit.php');
                $HasInsertPart0 = true;
            }
            // 转向机防尘罩	
            if ($name == 'Steering Boot') {
                //大小车型相同时，Steering Rack Bellow Kit与Steering Boot对应的GSP型号是通用关系时，只取Steering Rack Bellow Kit的数据
                $sql = "SELECT t.*, pro1.p_outnum outnum1,pro2.p_outnum outnum2 FROM (
                SELECT pe_p_id1 p_id1,pe_p_id2 p_id2 FROM pro_exchange
                UNION
                SELECT pemn_p_id1 p_id1,pemn_p_id2 p_id2 FROM pro_exchange_model_numidx
                ) t
                JOIN pro pro1 ON pro1.p_id = p_id1
                JOIN pro pro2 ON pro2.p_id = p_id2
                WHERE (pro1.p_outnum = '" . $item['ssc_outnum'] . "' OR pro2.p_outnum = '" . $item['ssc_outnum'] . "')
                ";
                $trows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
                $hasSteeringRackBellowKit = false;
                foreach ($trows as $trow) {
                    if ($trow['outnum1'] == $item['ssc_outnum']) {
                        if (in_array($trow['outnum2'], $outnums)) {
                            $hasSteeringRackBellowKit = true;
                            break;
                        }
                    } elseif ($trow['outnum2'] == $item['ssc_outnum']) {
                        if (in_array($trow['outnum1'], $outnums)) {
                            $hasSteeringRackBellowKit = true;
                            break;
                        }
                    }
                }
                if (!$hasSteeringRackBellowKit) {
                    include(__DIR__ . '/ss/SteeringBoot.php');
                }
                $HasInsertPart0 = true;
            }
            // 单拉杆, 拉杆球头
            if ($name == 'Tie Rod End') {
                include(__DIR__ . '/ss/TieRodEnd.php');
                $HasInsertPart0 = true;
            }
            //拉杆球头
            if ($name == 'Tie Rod Axle Joint') {
                include(__DIR__ . '/ss/TieRodAxleJoint.php');
                $HasInsertPart0 = true;
            }

            // 拉杆总成	
            if ($name == 'Rod Assembly') {
                include(__DIR__ . '/ss/RodAssembly.php');
                $HasInsertPart0 = true;
            }
            //球头 Ball Joint
            if ($name == 'Ball Joint') {
                if ($HasInsertPart0 === true && $insertPart1 === false) {
                    $insertPart1 = true;
                    $addRowCout = 3; // 转向系 前面多加几行
                    for ($i = $startRow; $i < ($startRow + $addRowCout); $i++) {
                        $isBreak = $this->addRowNum($sheet, 'Empty');
                        if ($isBreak) {
                            break;
                        } else {
                            $this->setBgColor($sheet, $i);
                        }
                    }
                }
                include(__DIR__ . '/ss/BallJoint.php');
            }

            //Track Control Arm  控制臂, 控制臂衬套	Control Arm Bush	
            if ($name == 'Track Control Arm' || $name == 'Control Arm') {
                if ($HasInsertPart0 === true && $insertPart1 === false) {
                    $insertPart1 = true;
                    $addRowCout = 3; // 转向系 前面多加几行
                    for ($i = $startRow; $i < ($startRow + $addRowCout); $i++) {
                        $isBreak = $this->addRowNum($sheet, 'Empty');
                        if ($isBreak) {
                            break;
                        } else {
                            $this->setBgColor($sheet, $i);
                        }
                    }
                }
                include(__DIR__ . '/ss/ControlArm.php');
            }

            // 控制臂衬套修理包	Control Arm Bush Kit
            if (in_array($name, [
                'Control Arm Bush',
                'Control Arm Bushing',
                'Control Arm Bush Kit',
                'Control Arm Bushing Kit',
            ]) && !in_array($currentKey, $skips)) {
                include(__DIR__ . '/ss/ControlArmBushKit.php');
            }
            // 控制臂套件
            if ($name == 'Suspension Repair Kit') {
                include(__DIR__ . '/ss/SuspensionRepairKit.php');
            }
            // 平衡杆 Rod/Strut,stabiliser,平衡/稳定杆衬套 Stabiliser Bushing,  平衡/稳定杆衬套修理包 Stabiliser Bushing Kit
            if ($name == 'Rod/Strut,stabiliser') {
                include(__DIR__ . '/ss/RodStrutstabiliser.php');
            }

            //平衡/稳定杆衬套 Stabiliser Bushing,  平衡/稳定杆衬套修理包 Stabiliser Bushing Kit
            if (($name === 'Stabiliser Bushing' || $name === 'Stabiliser Bushing Kit') && !in_array($currentKey, $skips)) {
                include(__DIR__ . '/ss/StabiliserBushing.php');
            }

            if ($maxInsertRowsCount > 0) {
                $regI = 0;
                for ($i = $startRow; $i < ($startRow + $maxInsertRowsCount); $i++) {
                    $isBreak = $this->addRowNum($sheet, 'Image',  $regI);
                    $this->setBgColor($sheet, $i);
                    $regI++;
                }
                $isBreak = $this->addRowNum($sheet, 'ImageEmpty');  //在型号块后再插入一行
                $this->setBgColor($sheet, $this->rowNum);
            }

        } //foreach   
        $this->buPageHeight($sheet, $this->rowNum); ///补最后一页高度
    }
    public function findRight($items, $item, &$skips)
    {
        $filteredItemsWithKeys = array_filter($items, function ($v, $ak) use ($item, $skips) {
            return $v['pos1'] === $item['pos1']
                && $v['ss_name'] === $item['ss_name']
                && $v['pos2'] === 'R'
                && $v['pos3'] === $item['pos3']
                && $v['pos4'] === $item['pos4']
                && $v['ss_remark'] === $item['ss_remark']
                && !in_array($ak, $skips)
                && $v['ssc_outnum'] !== $item['ssc_outnum'];
        }, ARRAY_FILTER_USE_BOTH);
        if ($filteredItemsWithKeys) {
            foreach ($filteredItemsWithKeys as $key => $value) {
                $skips[] = $key;
            }
            $newItem = $this->posAddToName($value);
            return $newItem;
        } else {
            return null;
        }
    }

    /**
     * 找父零件-记录集
     */
    public function findFatherRows($outnum)
    {
        $sql = sprintf("SELECT fs.*,pro1.p_outnum father_outnum,pro2.p_outnum son_outnum,cate2.en_name son_name from pro_fatherson fs
JOIN pro pro1 ON pro1.p_id = fs.pf_father_pid
JOIN pro pro2 ON pro2.p_id = fs.pf_son_pid
JOIN pro_cate cate2 ON cate2.id = pro2.p_cate
WHERE pro2.p_outnum = '%s'", $outnum);
        $rows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
        return $rows;
    }
    /**
     * 找子零件-记录集
     */
    public function findSonRows($outnum)
    {
        $sql = sprintf("SELECT fs.*,pro1.p_outnum father_outnum,pro2.p_outnum son_outnum,cate2.en_name son_name from pro_fatherson fs
JOIN pro pro1 ON pro1.p_id = fs.pf_father_pid
JOIN pro pro2 ON pro2.p_id = fs.pf_son_pid
JOIN pro_cate cate2 ON cate2.id = pro2.p_cate
WHERE pro1.p_outnum = '%s'", $outnum);
        $rows  = $this->db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
        return $rows;
    }
    /**
     * 找父零件-gsp型号集
     */
    public function findFatherOutnums($outnum)
    {
        $rows  = $this->findFatherRows($outnum);
        $data = [];
        foreach ($rows as $row) {
            $data[] = $row['father_outnum'];
        }
        return $data;
    }
    /**
     * 找子零件-gsp型号集
     */
    public function findSonOutnums($outnum)
    {
        $rows  = $this->findSonRows($outnum);
        $data = [];
        foreach ($rows as $row) {
            $data[] = $row['son_outnum'];
        }
        return $data;
    }
    /**  找中间产品 */
    public function findCenterNo($names, $items, $item, $rule, &$skips)
    {
        $filteredItemsWithKeys = array_filter($items, function ($v, $ak) use ($names, $item, $rule, $skips) {
            $result = isset($v['pos1']) && $v['pos1'] === $item['pos1']
                && isset($v['ss_name']) && in_array($v['ss_name'], $names)
                && isset($v['ssc_outnum']) && $v['ssc_outnum'] !== $item['ssc_outnum']
                && !in_array($ak, $skips);
            if (isset($rule['pos2'])) {
                $result = $result && $v['pos2'] == $rule['pos2'];
            }
            if (isset($rule['pos3'])) {
                $result = $result && $v['pos3'] == $rule['pos3'];
            }
            if (isset($rule['pos4'])) {
                $result = $result && $v['pos4'] == $rule['pos4'];
            }
            if (isset($rule['ss_remark_OR_empty'])) {
                $result = $result && ($v['ss_remark'] == $rule['ss_remark'] || $v['ss_remark'] == '');
            } else if (isset($rules['ss_remark'])) {
                $result = $result && $v['ss_remark'] == $rule['ss_remark'];
            }
            return $result;
        }, ARRAY_FILTER_USE_BOTH);
        return $filteredItemsWithKeys;
    }
    public function insertAny($sheet, $row, $item, $style)
    {
        $imgRow = $row;
        $towColWidth = 165;
        $gspNo = trim($item['ssc_outnum']);
        $oe = trim($item['ssc_oe']);
        $name = trim($item['ss_name']);
        $remark = trim($item['ss_remark']);
        $imgFile = $item['imgFile'];
        $offsetY = 0;
        $offsetX = 0;
        $flipOffsetX = 0;
        $col = $style['image']['col'];
        $colIndex = ($col === false) ? $style['image']['flipCol'] : $col;
        $flipColIndex = $style['image']['flipCol'] ?: $col;
        $textColIndex = ($colIndex < $flipColIndex) ? $colIndex: $flipColIndex;
        if (!$item['noimgFile']) {
            $info = getimagesize($imgFile, $info);
            $salc = $info[0] / $info[1];
            $height = $style['image']['height'] - 5;
            $width = $height * $salc;
            //宽度过大
            if ($width > 200) {
                $height = $height * (200 / $width);
                $width = 200;
            }
            if (!isset($style['image']['flip']) && !$style['image']['flip']) {
                if ($width < $towColWidth) {
                    $offsetX = ($towColWidth - $width) / 2; // 中间对齐
                } else {
                    if ($colIndex == 1) {
                        $offsetX = 0 + 5; //居左
                    } else if ($colIndex == 9) {
                        $offsetX = ($width - $towColWidth) * -1 - 5; //居右
                    } else {
                        $offsetX = ($width - $towColWidth) / 2 * -1; //居右
                    }
                }
            } else if ($style['image']['flip']){
                if ($col !== false) {
                    // 放两张图
                    $flipColIndex = $col;
                    if (($width *2) < $towColWidth) {
                        $offsetX = ($towColWidth / 2 - $width) / 2 + 1;
                        $flipOffsetX = ($towColWidth / 2 - $width) / 2 - 1;
                        $flipColIndex = $flipColIndex + 1;
                    } else {
                        if ($colIndex == 1) {
                            $offsetX = 0 + 5; //居左
                            $flipOffsetX = $offsetX + $width + 5;
                        } else if ($colIndex == 9) {
                            $flipOffsetX = ($towColWidth - $width) * -1 - 5; //居右
                            $offsetX = $flipOffsetX - $flipOffsetX - 5; 
                        } else {
                            $a = ($width * 2  - $towColWidth) / 2;
                            $offsetX = $a * -1 - 4;
                            $flipOffsetX = $offsetX + $width + 8;
                        }
                    }
                } else {
                    //只放一张图
                    if ($width < $towColWidth) {
                        $flipOffsetX = ($towColWidth - $width) / 2; // 中间对齐
                    } else {
                        if ($flipColIndex == 1) {
                            $flipOffsetX = 0 + 5; //居左
                        } else if ($flipColIndex == 9) {
                            $flipOffsetX = ($width - $towColWidth) * -1 - 5; //居右
                        } else {
                            $flipOffsetX = ($width - $towColWidth) / 2 * -1;
                        }
                    }
                }
            }

            $lineHeight = $height;
            $offsetY = 20;
        } else {
            $lineHeight = 80;
        }
        if ($style['image']['top']) {
            // 当行高大于图片高度时
            if (!isset($style['image']['lineHeight'])) {
                $this->activeLineHeight = $lineHeight;
            } elseif ($style['image']['lineHeight']) {
                if(isset($this->isSetHeightRows[$imgRow]) && $this->isSetHeightRows[$imgRow] > $height){
                    $offsetY = $offsetY + ($this->isSetHeightRows[$imgRow] - $height);
                }
            }
            $this->insertTextGspNo($sheet, $textColIndex, $row + 1, $gspNo);
            $this->insertTextOE($sheet, $textColIndex + 1, $row + 1, $oe);
            $this->insertTextName($sheet, $textColIndex, $row + 2, $name);
            $moreRemark = $this->findMoreRemark($item['ssc_make'], $item['model'], $gspNo);
            if ($moreRemark) {
                $this->insertTextRemark($sheet, $textColIndex, $row + 3, $moreRemark, 'left');
            } else {
                $this->insertTextRemark($sheet, $textColIndex, $row + 3, $remark, 'center');
            }
            if (!$item['noimgFile']) {
                if (isset($style['image']['flipRight']) && $style['image']['flipRight']) {
                    if ($col !== false) {
                        //镜像
                        $tmpFilename = $this->tmpDir . '/flip_' . md5($imgFile) . '.png';
                        $this->image->flipImage($imgFile, $tmpFilename);
                        $this->insertImage($sheet, $tmpFilename, $width, $height, $col, $row, $offsetX, $offsetY);
                    }
                    //右图(翻转)
                    if ($style['image']['flip']) {
                        $this->insertImage($sheet, $imgFile, $width, $height, $flipColIndex, $row, $flipOffsetX, $offsetY);
                    }
                } else {
                    if ($col !== false) {
                        $this->insertImage($sheet, $imgFile, $width, $height, $col, $row, $offsetX, $offsetY);
                    }
                    //右图(翻转)
                    if ($style['image']['flip']) {
                        //镜像
                        $tmpFilename = $this->tmpDir . '/flip_' . md5($imgFile) . '.png';
                        $this->image->flipImage($imgFile, $tmpFilename);
                        $this->insertImage($sheet, $tmpFilename, $width, $height, $flipColIndex, $row, $flipOffsetX, $offsetY);
                    }
                }
            }
        } else {
            
        }
        $this->setRowHeight($sheet, $imgRow, $lineHeight * PT_SALC + 22);
        $addRowCout = $remark ? 4 : 3;
        for ($i = $row; $i <= ($row + $addRowCout); $i++) {
            $this->setBgColor($sheet, $i);
        }
        return $addRowCout;
    }
    public function setBgColor($sheet, $row, $color = 'F4F4F4', $force = false)
    {
        //$sheet->getStyle("A{$row}:J{$row}")->getFill()->setFillType(Fill::FILL_SOLID);
        //$sheet->getStyle("A{$row}:J{$row}")->getFill()->getStartColor()->setRGB($color);


        //$range = "A{$row}:K{$row}";
        foreach (range('A', 'K') as $char) {
            $cell =   $char.$row;
            $style = $sheet->getStyle($cell);
            if (
                !$force
                //&& $style->getFill()->getFillType() == Fill::FILL_SOLID
                //&& $style->getFill()->getStartColor()->getARGB() != 'FFFFFFFF'
                && $sheet->getCell($cell)->getValue() != ''

            ) {
                //如果不是白色且不强制覆盖，则跳过;
            } else {
                $style->getFill()
                    ->setFillType(Fill::FILL_SOLID)
                    ->getStartColor()
                    ->setRGB($color);
            }
        }
    }

    public function posAddToName($item)
    {
        $name = $item['ss_name'];
        if (in_array($name, [
            'Control Arm Bushing',
            'Track Control Arm',
            'Control Arm Bushing Kit',
            'Control Arm Bush',
            'Control Arm',
            'Control Arm Bush Kit',
            'Ball Joint',
        ])) {
            switch ($name) {
                case 'Control Arm Bushing':
                    $name = 'Control Arm Bush';
                    break;
                case 'Track Control Arm':
                    $name = 'Control Arm';
                    break;
                case 'Control Arm Bushing Kit':
                    $name = 'Control Arm Bush Kit';
                    break;
            }
            if ($item['pos3'] == 'O') {
                $name = 'Outer ' . $name;
            } elseif ($item['pos3'] == 'I') {
                $name = 'Inner ' . $name;
            }
            if ($item['pos4'] == 'L') {
                $name = 'Lower ' . $name;
            } elseif ($item['pos4'] == 'U') {
                $name = 'Upper ' . $name;
            }
        }
        if (in_array($name, [
            'Stabiliser Bushing',
            'Stabiliser Bushing Kit',
            'Tie Rod End',
            'Control Arm Bush',
            'Control Arm',
            'Control Arm Bush Kit',
        ])) {
            if ($item['pos3'] == 'O') {
                $name = 'Outer ' . $name;
            } elseif ($item['pos3'] == 'I') {
                $name = 'Inner ' . $name;
            } elseif ($item['pos3'] == 'C') {
                $name = 'Centre ' . $name;
            }
        }
        $item['ss_name'] = $name;
        return $item;
    }

    public function inserText($fontSize, $angle, $font, $text, $savePath)
    {

        $bbox = imagettfbbox($fontSize, $angle, $font, $text);
        $textHeight = abs($bbox[7] - $bbox[1]); // 文字高度
        $textWidth = abs($bbox[2] - $bbox[0]);  // 文字宽度
        $textWidth += 10;

        $imgWidth = $textWidth;
        $imgHeight = $textHeight + 10;

        $img = imagecreatetruecolor($imgWidth, $imgHeight);
        imagesavealpha($img, true);
        $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
        imagefill($img, 0, 0, $transparent);

        $white = imagecolorallocate($img, 255, 255, 255);

        $x = ($imgWidth - $textWidth) / 2;
        $y = ($imgHeight + $textHeight) / 2;

        imagettftext($img, $fontSize, $angle, $x, $y, $white, $font, $text);
        imagepng($img, $savePath);
        imagedestroy($img);
        return [
            'width' => $imgWidth,
            'height' => $imgHeight,
        ];
    }
    public function imageTextSize($fontSize, $angle, $font, $text)
    {
        $bbox = imagettfbbox($fontSize, $angle, $font, $text);
        $left = min($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $right = max($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $top = min($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $bottom = max($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $textWidth = $right - $left;
        $textHeight = $bottom - $top;
        return [
            'top' => $top,
            'bottom' => $bottom,
            'left' => $left,
            'right' => $right,
            'width' => $textWidth,
            'height' => $textHeight,
        ];
    }

    public function insertTextFitWidthByImage($targetWidth, $angle, $font, $text, $image, $x, $y, $areaHeight, $maxFontSize = 40, $minFontSize = 12)
    {
        if(!$targetWidth || !$text){
            return [];
        }
        $fontSize = $maxFontSize;
        // 找出最合适的字体大小
        while ($fontSize >= $minFontSize) {
            $bbox = imagettfbbox($fontSize, $angle, $font, $text);
            $left = min($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
            $right = max($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
            $textWidth = $right - $left;

            if ($textWidth <= $targetWidth - 10) { // 预留边距
                break;
            }
            $fontSize--;
        }
        // 重新获取最终尺寸
        $bbox = imagettfbbox($fontSize, $angle, $font, $text);
        $left = min($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $right = max($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $top = min($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $bottom = max($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $textWidth = $right - $left;
        $textHeight = $bottom - $top;

        $imgWidth = $textWidth;
        $imgHeight = $textHeight;
        if ($imgWidth <= 0 || $imgHeight <= 0) {
            dump($targetWidth, $angle, $font, $text, $image, $x, $y, $areaHeight, $maxFontSize, $minFontSize);
        }
        $img = imagecreatetruecolor($imgWidth, $imgHeight);
        if ($img === false) {
            dump($targetWidth, $angle, $font, $text, $image, $x, $y, $areaHeight, $maxFontSize, $minFontSize);
        }
        imagesavealpha($img, true);
        $transparent = imagecolorallocatealpha($image, 0, 0, 0, 127);
        imagefill($img, 0, 0, $transparent);

        $white = imagecolorallocate($image, 255, 255, 255);
        $y = $y + $textHeight + ($areaHeight - $textHeight) / 2;

        imagettftext($image, $fontSize, $angle, $x, $y, $white, $font, $text);

        return [
            'fontSize' => $fontSize,
            'width' => $imgWidth,
            'height' => $imgHeight,
        ];
    }
    public function insertTextFitWidth($targetWidth, $angle, $font, $text, $savePath, $maxFontSize = 20, $minFontSize = 10)
    {
        $fontSize = $maxFontSize;
        // 找出最合适的字体大小
        while ($fontSize >= $minFontSize) {
            $bbox = imagettfbbox($fontSize, $angle, $font, $text);
            //$textWidth = abs($bbox[2] - $bbox[0]);
            $left = min($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
            $right = max($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
            $textWidth = $right - $left;

            if ($textWidth <= $targetWidth - 10) { // 预留边距
                break;
            }
            $fontSize--;
        }
        // 重新获取最终尺寸
        $bbox = imagettfbbox($fontSize, $angle, $font, $text);
        //$textWidth = abs($bbox[2] - $bbox[0]);
        //$textHeight = abs($bbox[7] - $bbox[1]);
        $left = min($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $right = max($bbox[0], $bbox[2], $bbox[4], $bbox[6]);
        $top = min($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $bottom = max($bbox[1], $bbox[3], $bbox[5], $bbox[7]);
        $textWidth = $right - $left;
        $textHeight = $bottom - $top;

        $imgWidth = $targetWidth;
        $imgHeight = $textHeight + 10;

        $img = imagecreatetruecolor($imgWidth, $imgHeight);
        imagesavealpha($img, true);
        $transparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
        imagefill($img, 0, 0, $transparent);

        $white = imagecolorallocate($img, 255, 255, 255);

        //$x = ($imgWidth - $textWidth) / 2;
        $x = 0;
        $y = ($imgHeight + $textHeight) / 2;

        imagettftext($img, $fontSize, $angle, $x, $y, $white, $font, $text);
        imagepng($img, $savePath);
        imagedestroy($img);

        return [
            'fontSize' => $fontSize,
            'width' => $imgWidth,
            'height' => $imgHeight,
        ];
    }


    public function insertImage($sheet, $jpgFilename, $width, $height, $col, $row, $offsetX = 0, $offsetY = 0)
    {
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $drawing = new Drawing();
        $drawing->setPath($jpgFilename);
        $drawing->setWorksheet($sheet);
        $drawing->setCoordinates($cell);
        $drawing->setOffsetX($offsetX);
        $drawing->setOffsetY($offsetY);
        $drawing->setWidth($width);
        //$drawing->setHeight($height); // 不建议同时设置
        $drawing->setResizeProportional(true); // 保持比例
    }

    public function insertModelHeaderText($sheet, $row, $item)
    {
        $modelsText = $item['make'];
        foreach ($item['models'] as $i => $value) {
            $modelsText .= "\n". $this->remarkSeq[$i] . ' ' .$value ;
        }
        $style = $sheet->getStyle(MODELS_REMARK_COL . $row);
        $style->getFont()->setSize(9);
        $style->getAlignment()->setWrapText(true); //自动换行
        $style->getAlignment()->setShrinkToFit(true);
        $sheet->setCellValue(MODELS_REMARK_COL . $row, trim($modelsText));
    }


    public function addRowNum($sheet, $type, $regI = '')
    {
        $result = false; // 是否有分页
        if ($type == 'Image' && $regI == 0) {
            $this->activeImageRow = $this->rowNum;
        }
        $activePageHeight = $this->getActivePageHeight($sheet);
        if ($activePageHeight > MAX_PAGE_HEIGHT) {
            if ($type == 'Image') {
                //超出一页 型号块
                $tmpPageHeight = $this->getActivePageHeight($sheet, $this->activePageStartRow, $this->activeImageRow - 1);
                $this->buPageHeight($sheet, $this->activeImageRow - 1); //补上一页高度
                //$this->setRowHeight($sheet, $this->activeImageRow - 1, MAX_PAGE_HEIGHT - $tmpPageHeight);
                $this->setBreak($sheet, $this->activeImageRow - 1, $type);
            } elseif ($type == 'ImageEmpty') {
                $this->activeImageEmptyRow = $this->rowNum;
            } elseif ($type != 'Header') {
                //超出一页 其他行 例间隔, 空行
                $tmpPageHeight = $this->getActivePageHeight($sheet, $this->activePageStartRow, $this->rowNum - 1);
                $this->setRowHeight($sheet, $this->rowNum - 1, MAX_PAGE_HEIGHT - $tmpPageHeight);
                $this->setBreak($sheet, $this->rowNum - 1, $type);
                $this->activeImageEmptyRow = 0;
            }
            $result = true;
        }
        $this->rowNum++;
        return $result; //有没有分页
    }

    //当前页面高度
    public function getActivePageHeight($sheet, $beginRow = 0, $endRow = 0)
    {
        $result = 0;
        if ($beginRow == 0) $beginRow = $this->activePageStartRow;
        if ($endRow == 0) $endRow = $this->rowNum;
        for ($i= $beginRow; $i <= $endRow; $i++) {
            $h = $this->getRowHeight($sheet, $i);
            $result += $h;
        }
        return $result;
    }



    //分页
    public function setBreak($sheet, $row, $type = '')
    {
        if ($type == 'Header') {
            if ($this->activeImageEmptyRow > 0) {
                $row = $row - 1;
            }
            $style = $sheet->getStyle('A'.$row);
            $fill = $style->getFill();
            $bgColor = $fill->getStartColor()->getRGB();
            if ($bgColor != 'F4F4F4') {
                $row = $row - 1;
            }
            $row = $this->buPageHeight($sheet, $row); ///补上一页高度
        }
        $this->activePageStartRow  = $row + 1;
        $colChar = $this->int2Excel(1);
        $sheet->setBreak($colChar . $row, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet::BREAK_ROW);
        return $row;
    }

    public function buPageHeight($sheet, $row)
    {
        //上一页高度不足
        $activePageHeight = $this->getActivePageHeight($sheet);
        if ($activePageHeight < MAX_PAGE_HEIGHT) {
            //if( MAX_PAGE_HEIGHT - $activePageHeight > 408) {
                //插入行
                while (($activePageHeight + DEFAULT_ROW_HEIGHT) < MAX_PAGE_HEIGHT) {
                    $this->addRowNum($sheet, 'Empty');
                    $this->setBgColor($sheet, $this->rowNum);
                    $row = $row + 1;
                    $activePageHeight = $this->getActivePageHeight($sheet, $this->activePageStartRow, $this->rowNum);
                }
            //}
            $activePageHeight = $this->getActivePageHeight($sheet);
            $this->setRowHeight($sheet, $this->rowNum - 1, MAX_PAGE_HEIGHT - $activePageHeight);
        }
        return $row;
    }    

    public function getRowHeight($sheet, $row)
    {
        $rowHeight = $sheet->getRowDimension($row)->getRowHeight();
        return $rowHeight > 0 ? $rowHeight : DEFAULT_ROW_HEIGHT;
    }

    public function setRowHeight($sheet, $row, $height)
    {
        if (!isset($this->isSetHeightRows[$row]) || $this->isSetHeightRows[$row] < $height) {
            $this->isSetHeightRows[$row] = $height;
            $sheet->getRowDimension($row)->setRowHeight($height);
        }
    }
    public function insertModelHeaderAll($headerTag, $sheet, $col, $row, $item){
        $make = $item['make'];
        $models = $item['models'];
        $hasMoreRemark = false;
        if ($headerTag > 1) {
            foreach ($models as $model) {
                if ($this->hasMoreRemark($make, $model)) {
                    $hasMoreRemark = true;
                }
            }
        }
        $fontBold = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        $fontUni = $this->staticDir . '/arial/arialuni.ttf';
        if (!file_exists($fontBold)) {
            dd($fontBold . ' 不存在');
        }
        if (!file_exists($font)) {
            dd($font . ' 不存在');
        }
        if (!file_exists($fontUni)) {
            dd($fontUni . ' 不存在');
        }
        include(__DIR__ . '/ss/header/' . $headerTag . '.php');
    }

    public function insertModelHeader1($sheet, $col, $row, $item)
    {
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        if ($row > 1) {
            $row = $this->setBreak($sheet, $row - 1, 'Header') + 1;
        }
        $row = $row + 1;
        $this->insertModelHeaderText($sheet, $row, $item);
        //间隔行
        $this->setRowHeight($sheet, $row - 1, 7 * PT_SALC);
        $this->setBgColor($sheet, $row - 1, 'FFFFFF');
        $this->setBgColor($sheet, $row, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'Header');
        //
        $this->insertImage($sheet, $this->modelHeader[1]['filename'], $this->modelHeader[1]['width'], $this->modelHeader[1]['height'], $col, $row, 0, 3, 'J');
        $this->setRowHeight($sheet, $row, $this->modelHeader[1]['height'] * PT_SALC + 18);
        $fontSize = 16 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $tmpFilename = $this->tmpDir . '/' . md5($item['make']) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['make'], $tmpFilename);
        $fitWidthY =  8 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 22, $fitWidthY);
        $fontSize = 14 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        //$font = $this->staticDir . '/arial/arialuni.TTF';
        //1
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][0]) . '.png';
        $text = $item['models'][0];// ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨
        $info = $this->insertTextFitWidth(718, $angle, $font, $text, $tmpFilename, 15, 12);
        $fitWidthY =  35 +  (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 18, $fitWidthY);

        $isBreak = $this->addRowNum($sheet, 'Header');
    }

    public function insertModelHeader2($sheet, $col, $row, $item)
    {
        if ($row > 1) {
            $row = $this->setBreak($sheet, $row - 1, 'Header') + 1;
        }
        $row = $row + 1;
        $this->insertModelHeaderText($sheet, $row, $item);
        //间隔行
        $this->setRowHeight($sheet, $row - 1, 7 * PT_SALC);
        $this->setBgColor($sheet, $row - 1, 'FFFFFF');
        $this->setBgColor($sheet, $row, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'Header');
        //
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $this->insertImage($sheet, $this->modelHeader[2]['filename'], $this->modelHeader[2]['width'], $this->modelHeader[2]['height'], $col, $row);
        $this->setRowHeight($sheet, $row, $this->modelHeader[2]['height'] * PT_SALC + 15);
        $fontSize = 16 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $tmpFilename = $this->tmpDir . '/' . md5($item['make']) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['make'], $tmpFilename);
        $fitWidthY =  6 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 22, $fitWidthY);
        $fontSize = 14 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        //1
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][0]) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['models'][0], $tmpFilename);
        $fitWidthY =  37 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 15, $fitWidthY);
        //2
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][1]) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['models'][1], $tmpFilename);
        $fitWidthY =  71 + (32 - $info['height']) / 2;

        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 10, $fitWidthY);

        $isBreak = $this->addRowNum($sheet, 'Header');
    }

    public function insertModelHeader4($sheet, $col, $row, $item)
    {
        if ($row > 1) {
            $row = $this->setBreak($sheet, $row - 1, 'Header') + 1;
        }
        $row = $row + 1;
        $this->insertModelHeaderText($sheet, $row, $item);
        //间隔行
        $this->setRowHeight($sheet, $row - 1, 7 * PT_SALC);
        $this->setBgColor($sheet, $row - 1, 'FFFFFF');
        $this->setBgColor($sheet, $row, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'Header');
        //
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $this->insertImage($sheet, $this->modelHeader[4]['filename'], $this->modelHeader[4]['width'], $this->modelHeader[4]['height'], $col, $row);
        $this->setRowHeight($sheet, $row, $this->modelHeader[4]['height'] * PT_SALC + 12);

        $fontSize = 16 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $tmpFilename = $this->tmpDir . '/' . md5($item['make']) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['make'], $tmpFilename);
        $fitWidthY =  6 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 22, $fitWidthY);
        $fontSize = 14 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        //1
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][0]) . '.png';
        $info = $this->insertTextFitWidth(550, $angle, $font, $item['models'][0], $tmpFilename, 20, 12);
        $fitWidthY =  36.5 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 15, $fitWidthY);
        //2
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][1]) . '.png';
        $info = $this->insertTextFitWidth(550, $angle, $font, $item['models'][1], $tmpFilename, 20, 12);
        $fitWidthY =  36.5 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 5, $row, 82, $fitWidthY);
        //3
        if(isset($item['models'][2]) && !empty($item['models'][2])) {
            $tmpFilename = $this->tmpDir . '/' . md5($item['models'][2]) . '.png';
            $info = $this->insertTextFitWidth(550, $angle, $font, $item['models'][2], $tmpFilename, 20, 12);
            $fitWidthY =  70 + (32 - $info['height']) / 2;
            $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 10, $fitWidthY);
        }
        //4
        if (isset($item['models'][3]) && !empty($item['models'][3])) {
            $tmpFilename = $this->tmpDir . '/' . md5($item['models'][3]) . '.png';
            $info = $this->insertTextFitWidth(550, $angle, $font, $item['models'][3], $tmpFilename, 20, 12);
            $fitWidthY =  70 + (32 - $info['height']) / 2;
            $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 5, $row, 77, $fitWidthY);
        }

        $isBreak = $this->addRowNum($sheet, 'Header');
    }

    public function insertModelHeader6($sheet, $col, $row, $item)
    {
        if ($row > 1) {
            $row = $this->setBreak($sheet, $row - 1, 'Header') + 1;
        }
        $row = $row + 1;
        $this->insertModelHeaderText($sheet, $row, $item);
        //间隔行
        $this->setRowHeight($sheet, $row - 1, 7 * PT_SALC);
        $this->setBgColor($sheet, $row - 1, 'FFFFFF');
        $this->setBgColor($sheet, $row, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'Header');
        //
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $this->insertImage($sheet, $this->modelHeader[6]['filename'], $this->modelHeader[6]['width'], $this->modelHeader[6]['height'], $col, $row);
        $this->setRowHeight($sheet, $row, $this->modelHeader[6]['height'] * PT_SALC + 15);
        $fontSize = 16 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $tmpFilename = $this->tmpDir . '/' . md5($item['make']) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['make'], $tmpFilename);
        $fitWidthY =  6 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 22, $fitWidthY);
        $fontSize = 12 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        //1
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][0]) . '.png';
        $info = $this->insertTextFitWidth(225, $angle, $font, $item['models'][0], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 18 , $fitWidthY);
        //2
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][1]) . '.png';
        $info = $this->insertTextFitWidth(225, $angle, $font, $item['models'][1], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 4, $row, 22, $fitWidthY);
        //3
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][2]) . '.png';
        $info = $this->insertTextFitWidth(200, $angle, $font, $item['models'][2], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 7, $row, 38, $fitWidthY);

        //4
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][3]) . '.png';
        $info = $this->insertTextFitWidth(225, $angle, $font, $item['models'][3], $tmpFilename, 18, 10);
        $fitWidthY =  63 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 12, $fitWidthY);
        //5
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][4]) . '.png';
        $info = $this->insertTextFitWidth(225, $angle, $font, $item['models'][4], $tmpFilename, 18, 10);
        $fitWidthY =  63 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 4, $row, 17, $fitWidthY);
        //6
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][5]) . '.png';
        $info = $this->insertTextFitWidth(225, $angle, $font, $item['models'][5], $tmpFilename, 18, 10);
        $fitWidthY =  63 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 7, $row, 32, $fitWidthY);

        $isBreak = $this->addRowNum($sheet, 'Header');

    }

    public function insertModelHeader9($sheet, $col, $row, $item)
    {
        if ($row > 1) {
            $row = $this->setBreak($sheet, $row - 1, 'Header') + 1;
        }
        $row = $row + 1;
        $this->insertModelHeaderText($sheet, $row, $item);
        //间隔行
        $this->setRowHeight($sheet, $row - 1, 7 * PT_SALC);
        $this->setBgColor($sheet, $row - 1, 'FFFFFF');
        $this->setBgColor($sheet, $row, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'Header');
        //
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $this->insertImage($sheet, $this->modelHeader[9]['filename'], $this->modelHeader[9]['width'], $this->modelHeader[9]['height'], $col, $row);
        $this->setRowHeight($sheet, $row, $this->modelHeader[9]['height'] * PT_SALC + 15);

        $fontSize = 16 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ArialCEBoldItalic.ttf';
        $tmpFilename = $this->tmpDir . '/' . md5($item['make']) . '.png';
        $info = $this->inserText($fontSize, $angle, $font, $item['make'], $tmpFilename);
        $fitWidthY =  6 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'] / HEAER_IMAGE_FD, $info['height'] / HEAER_IMAGE_FD, $col + 1, $row, 22, $fitWidthY);
        $fontSize = 12 * HEAER_IMAGE_FD;
        $angle = 0;
        $font = $this->staticDir . '/arial/ARIALI.TTF';
        //1
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][0]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][0], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 17, $fitWidthY);
        //2
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][1]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][1], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 4, $row, 22, $fitWidthY);
        //3
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][2]) . '.png';
        $info = $this->insertTextFitWidth(200, $angle, $font, $item['models'][2], $tmpFilename, 18, 10);
        $fitWidthY =  32 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 7, $row, 38, $fitWidthY);

        //4
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][3]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][3], $tmpFilename, 18, 10);
        $fitWidthY =  62 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 12, $fitWidthY);
        //5
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][4]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][4], $tmpFilename, 18, 10);
        $fitWidthY =  62 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 4, $row, 18, $fitWidthY);
        //6
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][5]) . '.png';
        $info = $this->insertTextFitWidth(200, $angle, $font, $item['models'][5], $tmpFilename, 18, 10);
        $fitWidthY =  62 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 7, $row, 34, $fitWidthY);

        //7
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][6]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][6], $tmpFilename, 18, 10);
        $fitWidthY =  95.5 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 1, $row, 5, $fitWidthY);
        //8
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][7]) . '.png';
        $info = $this->insertTextFitWidth(245, $angle, $font, $item['models'][7], $tmpFilename, 18, 10);
        $fitWidthY =  95.5 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 4, $row, 14, $fitWidthY);
        //9
        $tmpFilename = $this->tmpDir . '/' . md5($item['models'][8]) . '.png';
        $info = $this->insertTextFitWidth(200, $angle, $font, $item['models'][8], $tmpFilename, 18, 10);
        $fitWidthY =  95.5 + (32 - $info['height']) / 2;
        $this->insertImage($sheet, $tmpFilename, $info['width'], $info['height'], $col + 7, $row, 30, $fitWidthY);
        $isBreak = $this->addRowNum($sheet, 'Header');

    }

    public function fitWidthYByFontSite($fontSize, $bu = 0) {
        $result = 0;
        if($fontSize >= 16) {
            $result = 8;
        } elseif ($fontSize >= 15) {
            $result = 9;
        } elseif ($fontSize >= 14) {
            $result = 10.5;
        } elseif ($fontSize >= 13) {
            $result = 9.5;
        } elseif ($fontSize >= 12) {
            $result = 18;
        } elseif ($fontSize >= 11) {
            $result = 20;
        } elseif ($fontSize >= 10) {
            $result = 22;
        } else {
            $result = 22;
        }
        return $result + $bu;
    }


    //前桥图
    public function insertFrontAxle($sheet, $col, $row)
    {
        //
        $colChar = $this->int2Excel($col);
        $cell =  $colChar . $row;
        $pngFile = $this->staticDir . '/front.png';
        //$width = 79;
        $width = 70;
        $height = 67;
        $this->insertImage($sheet, $pngFile, $width, $height, $col, $row, 10);
        $this->setRowHeight($sheet, $row, $height * PT_SALC);
        $this->setBgColor($sheet, $row, 'F4F4F4');

        $isBreak = $this->addRowNum($sheet, 'FrontAxle');
    }

    //后桥图
    public function insertRearAxle($sheet, $col, $row, $type = '')
    {
        /*
        if ($type == 'noJg') {
            //间隔行
            $this->setBgColor($sheet, $row, 'F4F4F4');
            $isBreak = $this->addRowNum($sheet, 'RearAxle');
            $row = $row + 1;
        }*/
        //
        $pngFile = $this->staticDir . '/rear.png';
        $width = 70;
        $height = 67;
        $this->insertImage($sheet, $pngFile, $width, $height, $col, $row, 10);
        $this->setRowHeight($sheet, $row, $height * PT_SALC);
        $this->setBgColor($sheet, $row, 'F4F4F4');

        $isBreak = $this->addRowNum($sheet, 'RearAxle');
    }

    //间隔
    public function insertJgAxle($sheet, $col, $row)
    {
        $startRow = $row;
        $isBreak = false;
        //间隔行 添加3行
        for ($i = $startRow; $i < ($startRow + 3); $i++) {
            $isBreak = $this->addRowNum($sheet, 'JgAxle');
            if ($isBreak) {
                break;
            } else {
                $this->setBgColor($sheet, $i);
            }
        }

        if ($isBreak) {
            // 有分页
            $row = $this->rowNum;
        } else {
            $row = $startRow + 3;
        }
        //
        $colChar = $this->int2Excel($col);
        $pngFile = $this->staticDir . '/jg.png';
        $width = 820 * SCALING_FACTOR;
        $height = 30;
        $this->insertImage($sheet, $pngFile, $width, $height, $col, $row);
        $this->setRowHeight($sheet, $row, $height * PT_SALC);
        $isBreak = $this->addRowNum($sheet, 'JgAxle');

        //间隔行
        $this->setBgColor($sheet, $row + 1, 'FFFFFF');
        $isBreak = $this->addRowNum($sheet, 'JgAxle');
    }

    //GSP No 文本
    public function insertTextGspNo($sheet, $col, $row, $gspNo)
    {
        $cell = $this->int2Excel($col) . $row;
        $sheet->setCellValue($cell, $gspNo);

        $sheet->getStyle($cell)->applyFromArray([
            'fill' => [
                'fillType' => Fill::FILL_SOLID,
                'startColor' => ['argb' => 'FF004DA7'],
                'endColor' => ['argb' => 'FF004DA7']
            ],
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
                'vertical' => Alignment::VERTICAL_CENTER,
                'shrinkToFit' => true
            ],
            'font' => [
                'name' => 'Arial',
                'bold' => true,
                'color' => ['rgb' => Color::COLOR_WHITE]
            ],
        ]);
        // 插入检查号码文本
        $cellCheckGspNo = MODELS_REMARK_COL . $row;
        $checkGspNoValue = $sheet->getCell($cellCheckGspNo)->getValue() ?: '';
        $arr = [];
        if ($checkGspNoValue) {
            $arr = explode('/', $checkGspNoValue);
        }
        $arr[] = $gspNo;
        $arr = array_unique($arr);
        $sheet->setCellValue($cellCheckGspNo, implode('/', $arr));
        $sheet->getStyle($cellCheckGspNo)->applyFromArray([
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_LEFT,
                'shrinkToFit' => true
            ],
        ]);
    }

    //OE 文本
    public function insertTextOE($sheet, $col, $row, $oe)
    {
        if(empty($oe)) $oe = ' ';
        $font = 'Arial';
        $colChar = $this->int2Excel($col);
        $cell = $colChar . $row;
        $style = $sheet->getStyle($cell);
        $style->getFill()->setFillType(Fill::FILL_SOLID);
        $style->getFill()->getStartColor()->setRGB(Color::COLOR_WHITE);
        $style->getAlignment()->setShrinkToFit(true);
        $style->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
        $style->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
        $style->getFont()->setName($font);
        $sheet->setCellValue($cell, $oe);
    }

    //品名 文本
    public function insertTextName($sheet, $col, $row, $name)
    {
        $font = 'Arial';
        $colChar = $this->int2Excel($col);
        $cell = $colChar . $row . ':' . $this->int2Excel($col + 1) . $row;
        $sheet->mergeCells($cell);
        $cell = $colChar . $row;
        $style = $sheet->getStyle($cell);
        $style->getFill()->setFillType(Fill::FILL_SOLID);
        $style->getFill()->getStartColor()->setRGB('F6AC2D');
        $style->getAlignment()->setShrinkToFit(true);
        $style->getFont()->getColor()->setRGB('000000');
        $style->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
        $style->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
        $style->getFont()->setName($font);
        $sheet->setCellValue($cell, $name);
    }

    //区别 备注
    public function insertTextRemark($sheet, $col, $row, $remark, $hAlgin = 'center')
    {
        $font = 'Arial';
        //$font = 'Consolas';
        $fontSize = ($font == 'Arial') ? 9 : 8;
        $maxLineCharQty = ($font == 'Arial') ? 25 : 25;
        $maxPixelWidth = 150;
        $cell = '';
        if (strlen($remark) > 80 ) {
            if ($col == 1 ||  $col == 7) {
                $colChar = $this->int2Excel($col);
                $cell = $colChar . $row . ':' . $this->int2Excel($col + 2) . $row;
                $maxLineCharQty = ($font == 'Arial') ? 34 : 40;
                $maxPixelWidth = 225;
            } elseif ($col == 3 || $col == 9) {
                $colChar = $this->int2Excel($col - 1);
                $cell = $colChar . $row . ':' . $this->int2Excel($col + 1) . $row;
                $maxLineCharQty = ($font == 'Arial') ? 34 : 40;
                $maxPixelWidth = 225;
            } elseif ($col == 5) {
                $colChar = $this->int2Excel($col - 1);
                $cell = $colChar . $row . ':' . $this->int2Excel($col + 2) . $row;
                $maxLineCharQty = ($font == 'Arial') ? 44 : 53;
                $maxPixelWidth = 300;
            }
        } 
        if(!$cell){
            $colChar = $this->int2Excel($col);
            $cell = $colChar . $row . ':' . $this->int2Excel($col + 1) . $row;
        }
        $sheet->mergeCells($cell);
        $cell = $colChar . $row;
        $style = $sheet->getStyle($cell);
        $style->getFill()->setFillType(Fill::FILL_SOLID);
        $style->getFill()->getStartColor()->setRGB('D0CECE');
        $style->getFont()->getColor()->setRGB('000000');
        if ($hAlgin == 'center') {
            $style->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
        }
        $style->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
        $style->getFont()->setName($font);
        $remark = trim($remark);
        /*if (strlen($remark) > $maxLineCharQty && strpos($remark, "\n") === false) {
            $remark = $this->smart_chunk_split($remark, $maxLineCharQty, "\n"); //每25个字符换行
        }*/
        //$remark = $this->smart_chunk_split($remark, $maxLineCharQty, "\n"); //每25个字符换行
        //$remark = preg_replace('/(?=①|②|③|④|⑤|⑥|⑦|⑧|⑨)/u', "\n", $remark); // 添加换行符
        $arr = explode("\n", $remark);
        /*
        $newRemark = '';
        foreach ($arr as $k => $v) {
            if ($newRemark) $newRemark .= "\n";
            $newRemark .= $this->smart_chunk_split($v, $maxLineCharQty, "\n"); //每25个字符换行
        }*/
        $fontPath = $this->staticDir . '/arial/ARIALI.TTF';
        $fontUni = $this->staticDir . '/arial/arialuni.ttf';
        $newRemark = $this->smart_chunk_split_visual($remark, $fontUni, $fontSize, $maxPixelWidth);

        //计算行高
        $style->getAlignment()->setWrapText(true); //自动换行
        $lineHeight = 15; // 可调：一行的高度，Arial 默认大约是 13~15
        $lineCount = substr_count($newRemark, "\n") + 1;
        $rowHeight = $lineHeight * $lineCount;
        $this->setRowHeight($sheet, $row, $rowHeight);
        $style->getFont()->setSize($fontSize);
        $sheet->setCellValue($cell, $newRemark);
    }

    function smart_chunk_split_visual($text, $fontPath, $fontSize, $maxPixelWidth)
    {
        $text = trim($text);
        $lines = [];

        while (mb_strlen($text) > 0) {
            $textLen = mb_strlen($text);
            $fullLineTest = $text;
            $bbox = imagettfbbox($fontSize, 0, $fontPath, $fullLineTest);
            $fullWidth = $bbox[2] - $bbox[0];

            // ✅ 如果整段不超宽，整段作为一行
            if ($fullWidth <= $maxPixelWidth) {
                $lines[] = $text;
                break;
            }

            // 否则，我们按像素宽度裁剪，并尝试找断点
            $line = '';
            $lastValidSplitPos = -1;

            for ($i = 1; $i <= $textLen; $i++) {
                $part = mb_substr($text, 0, $i);
                $bbox = imagettfbbox($fontSize, 0, $fontPath, $part);
                $width = $bbox[2] - $bbox[0];

                if ($width > $maxPixelWidth) {
                    break;
                }

                $line = $part;

                $char = mb_substr($text, $i - 1, 1);
                $prevChar = $i >= 2 ? mb_substr($text, $i - 2, 1) : '';

                // ✅ 非字母数字，且不是小数点
                if (
                    !preg_match('/[\p{L}\p{N}]/u', $char) &&
                    !($char === '.' && preg_match('/\d/', $prevChar) && preg_match('/\d/', mb_substr($text, $i, 1)))
                ) {
                    $lastValidSplitPos = $i;
                }
            }

            if ($lastValidSplitPos !== -1) {
                $line = mb_substr($text, 0, $lastValidSplitPos);
                $text = mb_substr($text, $lastValidSplitPos);
            } else {
                // 强制断开（没有合法断点）
                $text = mb_substr($text, mb_strlen($line));
            }

            $lines[] = $line;
        }

        return implode("\n", $lines);
    }


    function smart_chunk_split($text, $maxLineCharQty)
    {
        $lines = [];
        $text = trim($text);
        while (mb_strlen($text) > $maxLineCharQty) {
            $chunk = mb_substr($text, 0, $maxLineCharQty);
            $lastSplitPos = -1;

            // 找最后一个非字母数字字符的位置
            $matches = [];
            $len = mb_strlen($text);
            for ($i = 0; $i < $len; $i++) {
                $char = mb_substr($text, $i, 1);
                if (!preg_match('/[\p{L}\p{N}]/u', $char)) {
                    $matches[] = ['char' => $char, 'pos' => $i];
                }
            }
            foreach ($matches as $match) {
                if ($match['pos'] >= (int)($maxLineCharQty * 0.6) && $match['pos'] <= $maxLineCharQty) {
                    $lastSplitPos = $match['pos'];
                }
            }
            if ($lastSplitPos !== -1) {
                $lines[] = mb_substr($text, 0, $lastSplitPos + 1);
                $text = mb_substr($text, $lastSplitPos + 1);
            } else {
                // 强制断开
                $lines[] = $chunk;
                $text = mb_substr($text, $maxLineCharQty);
            }
        }

        if (mb_strlen($text) > 0) {
            $lines[] = $text;
        }

        return implode("\n", $lines);
    }
}