You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Excel导出签名图片失败 仅显示路径不显示实际图片

问题根源

你当前代码有3个核心错误,导致签名图片无法正常导出:

  • 导出类没有实现WithDrawings接口,就算写了drawings()方法,Laravel Excel也不会识别执行
  • drawings()方法里写的是签名存储的文件夹路径,不是单张签名图片的完整路径,而且坐标写死在B3单元格,没法批量匹配每一行的签名列
  • 默认查询返回的signature字段是数据库里存的路径字符串,没有做清空处理,导出后会直接显示路径文本
导出功能修复方案

按以下步骤调整代码即可实现预期效果:

  1. 引入并实现WithDrawings、WithEvents接口,前者负责识别图片导出逻辑,后者用来批量设置行高,避免图片显示不全
  2. 提前在构造方法中查询所有签名数据,避免重复查库,遍历数据时把signature字段置空,防止导出路径字符串
  3. 遍历所有签名记录,给每行D列(签名列)生成对应的图片对象,拼接单张图片的完整路径,做好文件存在校验避免报错
  4. 批量设置数据行的行高,匹配图片尺寸,同时补上缺失的列宽配置

修正后的Export类代码如下:

<?php

namespace App\Exports;

use App\Models\signature;
use Maatwebsite\Excel\Concerns\FromCollection;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
// 新增引入图片导出、事件相关接口
use Maatwebsite\Excel\Concerns\WithDrawings;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;

class SignatureExport implements FromCollection, WithHeadings, WithColumnWidths, WithDrawings, WithEvents
{
    /**
     * 存储签名数据集,供其他方法复用避免重复查询
     */
    protected $signatures;

    public function __construct()
    {
        $this->signatures = signature::all();
    }

    /**
    * @return \Illuminate\Support\Collection
    */
    public function collection()
    {
        // 清空signature字段值,避免导出路径字符串
        return $this->signatures->map(function($item) {
            $item->signature = '';
            return $item;
        });
    }

    /**
     * 批量生成所有行的签名图片对象
     */
    public function drawings()
    {
        $drawings = [];
        // 表头占第1行,业务数据从第2行开始
        foreach ($this->signatures as $index => $sign) {
            $row = $index + 2;
            $imagePath = public_path('/uploads/signatures/' . $sign->signature);
            // 跳过不存在的图片,避免导出报错
            if (!file_exists($imagePath)) continue;

            $drawing = new Drawing();
            $drawing->setName('signature');
            $drawing->setDescription('User signature');
            $drawing->setPath($imagePath);
            $drawing->setHeight(90);
            // 定位到当前行的D列(签名列)
            $drawing->setCoordinates('D' . $row);
            // 设置边距避免图片贴单元格边框
            $drawing->setOffsetX(5);
            $drawing->setOffsetY(5);
            $drawings[] = $drawing;
        }
        return $drawings;
    }

    public function headings(): array
    {
        return [
            'id',
            'name',
            'description',
            'signature',
            'created_at',
            'updated_at',
        ];
    }

    public function columnWidths(): array
    {
        return [
            'A' => 30,
            'B' => 30,        
            'C' => 30,
            'D' => 30,    
            'E' => 30,
            'F' => 30, // 补全updated_at对应列的宽度配置
        ];
    }

    /**
     * 批量设置行高,保证图片完整显示
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function(AfterSheet $event) {
                $totalRows = count($this->signatures) + 1;
                // 从第2行开始统一设置行高适配图片尺寸
                for ($i = 2; $i <= $totalRows; $i++) {
                    $event->sheet->getRowDimension($i)->setRowHeight(80);
                }
            },
        ];
    }
}

原有控制器代码不需要调整,如果需要导出.xls格式,把download方法里的文件名后缀改成.xls即可。

对应场景的Excel导入实现

带签名图片的Excel导入核心逻辑是提取表格内嵌图片保存到本地,再关联到对应行数据,实现步骤如下:

  1. 生成导入类,实现ToModel、WithHeadingRow、WithEvents接口
  2. 在AfterSheet事件中遍历工作表内所有图片,筛选出签名列的图片保存到本地签名目录,记录图片和行号的映射关系
  3. 写入模型数据时,根据当前行号取出对应图片的存储文件名,存入数据库

基础Import类代码示例:

<?php

namespace App\Imports;

use App\Models\signature;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use Illuminate\Support\Str;

class SignatureImport implements ToModel, WithHeadingRow, WithEvents
{
    // 存储行号和对应签名图片文件名的映射
    protected $rowSignMap = [];

    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function(AfterSheet $event) {
                $sheet = $event->sheet->getDelegate();
                // 遍历所有嵌入图片
                foreach ($sheet->getDrawingCollection() as $drawing) {
                    $coordinate = $drawing->getCoordinates();
                    $column = substr($coordinate, 0, 1);
                    // 只处理D列(签名列)的图片
                    if ($column != 'D') continue;

                    $row = substr($coordinate, 1);
                    // 生成唯一文件名存储
                    $extension = $drawing->getExtension() ?: 'png';
                    $filename = Str::random(20) . '.' . $extension;
                    $savePath = public_path('uploads/signatures/' . $filename);
                    file_put_contents($savePath, file_get_contents($drawing->getPath()));
                    $this->rowSignMap[$row] = $filename;
                }
            }
        ];
    }

    public function model(array $row)
    {
        // 静态变量记录当前处理行号,表头占第1行,数据从第2行开始
        static $currentRow = 2;
        $signFile = $this->rowSignMap[$currentRow] ?? '';
        $currentRow++;

        return new signature([
            'name' => $row['name'],
            'description' => $row['description'],
            'signature' => $signFile,
        ]);
    }
}

控制器导入方法参考:

public function importexcel(Request $request)
{
    $request->validate([
        'file' => 'required|file|mimes:xls,xlsx'
    ]);
    Excel::import(new SignatureImport, $request->file('file'));
    return back()->with('success', '导入成功');
}

内容的提问来源于stack exchange,提问作者JUSTIN CHUA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:21:14