| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 | <?phpnamespace app\common\util;use PhpOffice\PhpSpreadsheet\Reader\Xlsx;use PhpOffice\PhpSpreadsheet\Reader\Xls;use PhpOffice\PhpSpreadsheet\IOFactory;use PhpOffice\PhpSpreadsheet\Cell\Coordinate;use PhpOffice\PhpSpreadsheet\Spreadsheet;use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;use PhpOffice\PhpSpreadsheet\Cell\DataType;use PhpOffice\PhpSpreadsheet\Style\Fill;use PhpOffice\PhpSpreadsheet\Style\Color;use PhpOffice\PhpSpreadsheet\Style\Alignment;use PhpOffice\PhpSpreadsheet\Style\Border;use PhpOffice\PhpSpreadsheet\Style\NumberFormat;use think\facade\Log;class ExcelHelper extends SingleObjectClass{    public $columnNameArray = [];    /**     * 使用PhpSpreadsheet导入     *     * @param string $file 文件地址     * @param int $sheet 工作表sheet(传0则获取第一个sheet)     * @param int $columnCnt 列数(传0则自动获取最大列)     * @param array $options 操作选项     *                          array mergeCells 合并单元格数组     *                          array formula    公式数组     *                          array format     单元格格式数组     *     * @return array     * @throws Exception     */    public function importExecl(string $file = '', int $sheet = 0, int $columnCnt = 0, &$options = [])    {        try {            /* 转码 */            $file = iconv("utf-8", "gb2312", $file);            if (empty($file) or !file_exists($file)) {                throw new \Exception('文件不存在!');            }            /** @var Xlsx $objRead */            $objRead = IOFactory::createReader('Xlsx');            if (!$objRead->canRead($file)) {                /** @var Xls $objRead */                $objRead = IOFactory::createReader('Xls');                if (!$objRead->canRead($file)) {                    throw new \Exception('只支持导入Excel文件!');                }            }            /* 如果不需要获取特殊操作,则只读内容,可以大幅度提升读取Excel效率 */            empty($options) && $objRead->setReadDataOnly(true);            /* 建立excel对象 */            $obj = $objRead->load($file);            /* 获取指定的sheet表 */            $currSheet = $obj->getSheet($sheet);            if (isset($options['mergeCells'])) {                /* 读取合并行列 */                $options['mergeCells'] = $currSheet->getMergeCells();            }            if (0 == $columnCnt) {                /* 取得最大的列号 */                $columnH = $currSheet->getHighestColumn();                /* 兼容原逻辑,循环时使用的是小于等于 */                $columnCnt = Coordinate::columnIndexFromString($columnH);            }            /* 获取总行数 */            $rowCnt = $currSheet->getHighestRow();            $data = [];            /* 读取内容 */            for ($_row = 1; $_row <= $rowCnt; $_row++) {                $isNull = true;                for ($_column = 1; $_column <= $columnCnt; $_column++) {                    $cellName = Coordinate::stringFromColumnIndex($_column);                    $cellId = $cellName . $_row;                    $cell = $currSheet->getCell($cellId);                    if (isset($options['format'])) {                        /* 获取格式 */                        $format = $cell->getStyle()->getNumberFormat()->getFormatCode();                        /* 记录格式 */                        $options['format'][$_row][$cellName] = $format;                    }                    if (isset($options['formula'])) {                        /* 获取公式,公式均为=号开头数据 */                        $formula = $currSheet->getCell($cellId)->getValue();                        if (0 === strpos($formula, '=')) {                            $options['formula'][$cellName . $_row] = $formula;                        }                    }                    if (isset($format) && 'm/d/yyyy' == $format) {                        /* 日期格式翻转处理 */                        $cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd');                    }                    $data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue());                    if (!empty($data[$_row][$cellName])) {                        $isNull = false;                    }                }                /* 判断是否整行数据为空,是的话删除该行数据 */                if ($isNull) {                    unset($data[$_row]);                }            }            return $data;        } catch (\Exception $e) {            throw $e;        }    }    /**     * PhpSpreadsheet Excel导出,     *     * @param array $datas 导出数据,格式['A1' => 'XXXX公司报表', 'B1' => '序号']     * @param string $fileName 导出文件名称     * @param array $options 操作选项,例如:     *                           bool   print       设置打印格式     *                           bool   defaultWrap  默认换行,true或false     *                           bool   defaultAlignCenter  默认居中,true或false     *                           number defaultFontSize  默认字体大小     *                           string freezePane  锁定行数,例如表头为第一行,则锁定表头输入A2     *                           array  setARGB     设置背景色,例如['A1', 'C1']     *                           array  setWidth    设置宽度,例如['A' => 30, 'C' => 20]     *                           bool|string   setBorder   设置单元格边框 A1:B5     *                           array  mergeCells  设置合并单元格,例如['A1:J1' => 'A1:J1']     *                           array  formula     设置公式,例如['F2' => '=IF(D2>0,E42/D2,0)']     *                           array  format      设置格式,整列设置,例如['A' => 'General','B'=>'number']     *                           array  alignCenter 设置居中样式,例如['A1', 'A2']     *                           array  bold        设置加粗样式,例如['A1', 'A2']     *                           array  wrap        设置换行,例如['A1', 'A2']     *                           array  rowHeight   设置行高,例如['9'=>"20"]     *                           array  fontSize   设置行高,例如['A1'=>"20"]     *                           string savePath    保存路径,设置后则文件保存到服务器,不通过浏览器下载     */    public function exportExcel(array $datas, string $fileName = '', array $options = []): bool    {        try {            if (empty($datas)) {                return false;            }            set_time_limit(0);            /** @var Spreadsheet $objSpreadsheet */            $objSpreadsheet = app(Spreadsheet::class);            /* 设置默认文字居左,上下居中 */            $styleArray = [                'alignment' => [                    'horizontal' => Alignment::HORIZONTAL_LEFT,                    'vertical' => Alignment::VERTICAL_CENTER,                ],            ];            $objSpreadsheet->getDefaultStyle()->applyFromArray($styleArray);            /* 设置Excel Sheet */            $activeSheet = $objSpreadsheet->setActiveSheetIndex(0);            /* 打印设置 */            if (isset($options['print']) && $options['print']) {                /* 设置打印为A4效果 */                $activeSheet->getPageSetup()->setPaperSize(PageSetup:: PAPERSIZE_A4);                /* 设置打印时边距 */                $pValue = 1 / 2.54;                $activeSheet->getPageMargins()->setTop($pValue / 2);                $activeSheet->getPageMargins()->setBottom($pValue * 2);                $activeSheet->getPageMargins()->setLeft($pValue / 2);                $activeSheet->getPageMargins()->setRight($pValue / 2);            }            /* 行数据处理 */            foreach ($datas as $sKey => $sItem) {                /* 默认文本格式 */                $pDataType = DataType::TYPE_STRING;                /* 设置单元格格式 */                if (isset($options['format']) && !empty($options['format'])) {                    $colRow = Coordinate::coordinateFromString($sKey);                    /* 存在该列格式并且有特殊格式 */                    if (isset($options['format'][$colRow[0]]) &&                        NumberFormat::FORMAT_GENERAL != $options['format'][$colRow[0]]) {                        $activeSheet->getStyle($sKey)->getNumberFormat()                            ->setFormatCode($options['format'][$colRow[0]]);                        if (false !== strpos($options['format'][$colRow[0]], '0.00') &&                            is_numeric(str_replace(['¥', ','], '', $sItem))) {                            /* 数字格式转换为数字单元格 */                            $pDataType = DataType::TYPE_NUMERIC;                            $sItem = str_replace(['¥', ','], '', $sItem);                        }                    } elseif (is_int($sItem) || is_numeric($sItem)) {                        $pDataType = DataType::TYPE_NUMERIC;                    }                }                $activeSheet->setCellValueExplicit($sKey, $sItem, $pDataType);                /* 存在:形式的合并行列,列入A1:B2,则对应合并 */                if (false !== strstr($sKey, ":")) {                    $options['mergeCells'][$sKey] = $sKey;                }                /* 设置换行 */                if (isset($options['defaultWrap']) && !empty($options['defaultWrap'])) {                    $activeSheet->getStyle($sKey)->getAlignment()->setWrapText(true);                }                /* 设置字体 */                if (isset($options['defaultFontSize']) && !empty($options['defaultFontSize'])) {                    $activeSheet->getStyle($sKey)->getFont()->setSize($options["defaultFontSize"]);                }                /* 设置居中 */                if (isset($options['defaultAlignCenter']) && !empty($options['defaultAlignCenter'])) {                    $styleArray = [                        'alignment' => [                            'horizontal' => Alignment::HORIZONTAL_CENTER,                            'vertical' => Alignment::VERTICAL_CENTER,                        ],                    ];                    $activeSheet->getStyle($sKey)->applyFromArray($styleArray);                }            }            unset($datas);            /* 设置锁定行 */            if (isset($options['freezePane']) && !empty($options['freezePane'])) {                $activeSheet->freezePane($options['freezePane']);                unset($options['freezePane']);            }            /* 设置宽度 */            if (isset($options['setWidth']) && !empty($options['setWidth'])) {                foreach ($options['setWidth'] as $swKey => $swItem) {                    $activeSheet->getColumnDimension($swKey)->setWidth($swItem);                }                unset($options['setWidth']);            }            /* 设置背景色 */            if (isset($options['setARGB']) && !empty($options['setARGB'])) {                foreach ($options['setARGB'] as $sItem) {                    $activeSheet->getStyle($sItem)                        ->getFill()->setFillType(Fill::FILL_SOLID)                        ->getStartColor()->setARGB(Color::COLOR_YELLOW);                }                unset($options['setARGB']);            }            /* 设置公式 */            if (isset($options['formula']) && !empty($options['formula'])) {                foreach ($options['formula'] as $fKey => $fItem) {                    $activeSheet->setCellValue($fKey, $fItem);                }                unset($options['formula']);            }            /* 合并行列处理 */            if (isset($options['mergeCells']) && !empty($options['mergeCells'])) {                $activeSheet->setMergeCells($options['mergeCells']);                unset($options['mergeCells']);            }            /* 设置居中 */            if (isset($options['alignCenter']) && !empty($options['alignCenter'])) {                $styleArray = [                    'alignment' => [                        'horizontal' => Alignment::HORIZONTAL_CENTER,                        'vertical' => Alignment::VERTICAL_CENTER,                    ],                ];                foreach ($options['alignCenter'] as $acItem) {                    $activeSheet->getStyle($acItem)->applyFromArray($styleArray);                }                unset($options['alignCenter']);            }            /* 设置加粗 */            if (isset($options['bold']) && !empty($options['bold'])) {                foreach ($options['bold'] as $bItem) {                    $activeSheet->getStyle($bItem)->getFont()->setBold(true);                }                unset($options['bold']);            }            /* 设置换行 */            if (isset($options['wrap']) && !empty($options['wrap'])) {                foreach ($options['wrap'] as $acItem) {                    $activeSheet->getStyle($acItem)->getAlignment()->setWrapText(true);                }                unset($options['wrap']);            }            //设置行高 rowHeight            if (isset($options['rowHeight']) && !empty($options['rowHeight'])) {                foreach ($options['rowHeight'] as $key => $item) {                    $activeSheet->getRowDimension($key)->setRowHeight($item);                }                unset($options['rowHeight']);            }            /* 设置字体大小 */            if (isset($options['fontSize']) && !empty($options['fontSize'])) {                foreach ($options['fontSize'] as $key => $value) {                    $activeSheet->getStyle($key)->getFont()->setSize($value);                }                unset($options['fontSize']);            }            /* 设置单元格边框,整个表格设置即可,必须在数据填充后才可以获取到最大行列 */            if (isset($options['setBorder']) && $options['setBorder']) {                $border = [                    'borders' => [                        'allBorders' => [                            'borderStyle' => Border::BORDER_THIN, // 设置border样式                            'color' => ['argb' => 'FF000000'], // 设置border颜色                        ],                    ],                ];                if ($options['setBorder'] === true) {                    $setBorder = 'A1:' . $activeSheet->getHighestColumn() . $activeSheet->getHighestRow();                } else {                    $setBorder = $options['setBorder'];                }                $activeSheet->getStyle($setBorder)->applyFromArray($border);                unset($options['setBorder']);            }            $fileName = !empty($fileName) ? $fileName : (date('YmdHis') . '.xlsx');            if (!isset($options['savePath'])) {                /* 直接导出Excel,无需保存到本地,输出07Excel文件 */                header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');                header(                    "Content-Disposition:attachment;filename=" . iconv(                        "utf-8", "GB2312//TRANSLIT", $fileName                    )                );                header('Cache-Control: max-age=0');//禁止缓存                $savePath = 'php://output';            } else {                $savePath = $options['savePath'];            }            if (ob_get_length() > 0) {                ob_clean();                ob_start();            }            $objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx');            $objWriter->save($savePath);            /* 释放内存 */            $objSpreadsheet->disconnectWorksheets();            unset($objSpreadsheet);            if (ob_get_length() > 0) {                ob_end_flush();            }            return true;        } catch (Exception $e) {            return false;        }    }    public function __construct()    {        $this->setColumnName();    }    private function setColumnName()    {        $columnNameArr = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];        $columnNameArrLen = count($columnNameArr);        $firstWord = "";        for ($i = 0; $i < 500; $i++) {            if ($i % $columnNameArrLen == 0 && $i != 0) {                $firstWord = $columnNameArr[$i / $columnNameArrLen - 1];            }            $this->columnNameArray[] = $firstWord . $columnNameArr[$i % $columnNameArrLen];        }    }}
 |