fastadmin实现海报批量生成、邮件批量发送

记录一个海报批量生成、邮件批量发送功能开发,业务场景如下:

国外客户做观展预登记,工作人员通过后台,批量给这些观众生成入场证件并发送到观众登记的邮箱,以方便观众入场时快速进场。证件信息包含入场二维码、姓名;需要批量生成证件和批量发送邮件功能。

实现步骤大概如下:

index页面增加三个按钮,三个按钮的html如下:

html 复制代码
 <a class="btn btn-info btn-change btn-start" data-params="" data-url="miniform/guojihaibao/getdata" href="javascript:;"><i class="fa fa-play"></i> 批量获取登记数据</a>
                        <a class="btn btn-success btn-disabled disabled btn-selected" href="javascript:;"><i class="fa fa-magic"></i> 批量生成海报</a> 
                        <a class="btn btn-warning btn-disabled disabled btn-sendemail" href="javascript:;"><i class="fa fa-leaf"></i> 批量发送邮件</a>

1、批量获取登记数据;

后端

php 复制代码
    public function getdata(){
        $row = $this->model->query("SELECT a.name,a.email,a.qrcode 
FROM fa_miniform_di53jieguojimingjiajudongguanzhanlanhui a LEFT JOIN fa_haibao_guoji b
ON a.email=b.email
WHERE b.email IS NULL AND lang='en';");
        // dump($row);exit;
        if(!$row) $this->error('没有登记数据');
        $insert = $this->model->insertAll($row);
        if($insert){
            $this->success('同步了'.count($row).'条数据');
        }
    }

2、批量生成海报;

前端JS

javascript 复制代码
 // 批量生成海报
            $(document).on("click", ".btn-selected", function () {
                let ids = Table.api.selectedids(table) //获取选中的条目ID集合
                ids.forEach(function(value,index) {
                    let row = Table.api.getrowbyid(table, value) //根据主键ID获取行数据                
                    if(row.url_image){
                        Toastr.error(row.name+'已生成海报');
                        return false;
                    }
                    $.ajax({
                        type: "GET",
                        url: "miniform/guojihaibao/get_poster" + '/ids/' + value, 
                        cache: false,
                        success: function(data) {
                            Toastr.info(data.msg);
                        }
                      });
                });
                table.bootstrapTable('refresh',{});
            });

后端

php 复制代码
    //生成海报
    public function get_poster($ids=null){
        if(!$ids) $this->error('ids参数缺失');
        $row = $this->model->get($ids);
        $fileUrl = '/uploads/qrcode/haibao/'. $row->qrcode.'.jpg';
        $filename = ROOT_PATH .'public'. $fileUrl;
        //生成用户二维码
        $qrInfo = Haibao::buildQrcode($row->qrcode,'');
        $config = array(
            'image'=>array(
                array(
                    'url'=>$qrInfo,     //二维码地址
                    'is_yuan'=>false,          //true图片圆形处理
                    'stream'=>0,
                    'top'=>1140,
                    'right'=>0,
                    'width'=>500,             //图像宽
                    'height'=>500,            //图像高
                    'opacity'=>100            //透明度
                ),
            ),
            'text'=>array(
                array(
                    // 'text'=>$userInfo['invite_code'],            //文字内容
                    'text'=>$row->name,
                    'left'=>-1,                              //小于0为水平居中      
                    'top'=>1750,
                    'fontSize'=>38,                         //字号
                    'fontColor'=>'88, 133, 44',                //字体颜色
                    'angle'=>0,
                    'fontPath'=>ROOT_PATH.'/public/assets/fonts/SourceHanSansK-Regular.ttf',     //字体文件
                )
            ),
            'background'=>cdnurl($this->background,true),          //背景图
        );
        Haibao::createPoster($config,$filename);
        $url = cdnurl($fileUrl,true);
        
        if($url){
            $update = $this->model->save(['url_image'=>$fileUrl],['id'=>$ids]);
            if($update) $this->success('生成成功',$url);
        }
    }

其中生成二维码和生成海报引入了另外一个类文件Haibao

php 复制代码
<?php

namespace app\admin\model\call;

use think\Model;
use think\Response;
use traits\model\SoftDelete;

class Haibao extends Model
{

    use SoftDelete;

    

    // 表名
    protected $name = 'haibao';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'integer';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = 'deletetime';

    // 追加属性
    protected $append = [

    ];
    

    public static function init()
    {
        self::afterWrite(function ($row) {
        });
        self::afterDelete(function ($row) {
        });
        self::afterInsert(function ($row) {
            // dump($row['text1']);exit;
            
        });
        self::afterUpdate(function ($row) {
        });
    }

    // 生成二维码
    public static function buildQrcode($text,$label)
    {
        $params = [
            'text'           => $text,
            'size'           => 350,    //大小
            'padding'        => 15,    //内边距
            'errorlevel'     => 'medium',   //容错级别:low-低   medium-中等   quartile-高   high-超高
            'foreground'     => "#000000",     //前景色
            'background'     => "#ffffff",  //背景色
            'logo'           => 0,    //Logo:1-显示,0-不显示
            'logosize'       => '',  //Logo大小
            'label'          => $label, //标签
            'labelfontsize'  => 14, //标签大小
            'labelalignment' => 'center',    //标签水平位置:left-左  center-中   right-右
        ];

        $qrCode = \addons\qrcode\library\Service::qrcode($params);

        $response = Response::create()->header("Content-Type", "image/png");

        // 直接显示二维码
        header('Content-Type: ' . $qrCode->getContentType());
        $response->content($qrCode->writeString());

        // 写入到文件
        $fileUrl = '/uploads/qrcode/haibao/' . md5(implode('', $params)) . '.png';
        $filePath = ROOT_PATH .'public'. $fileUrl;
        if (!file_exists(ROOT_PATH .'public/uploads/qrcode/')) mkdir (ROOT_PATH .'public/uploads/qrcode/',0777,true); 
        if (!file_exists(ROOT_PATH .'public/uploads/qrcode/haibao/')) mkdir (ROOT_PATH .'public/uploads/qrcode/haibao/',0777,true); 
        
        $qrCode->writeFile($filePath);

        return $filePath;
    }

    
    /**
     * 生成宣传海报
     * @param array  参数,包括图片和文字
     * @param string  $filename 生成海报文件名,不传此参数则不生成文件,直接输出图片
     * @return [type] [description]
     */
    public static function createPoster($config = array() , $filename = "") {
        //如果要看报什么错,可以先注释调这个header
        //if(empty($filename)) header("content-type: image/png");
        if (empty($filename)) header("content-type: image/png");
        $imageDefault = array(
            'left' => 0,
            'top' => 0,
            'right' => 0,
            'bottom' => 0,
            'width' => 100,
            'height' => 100,
            'opacity' => 100
        );
        $textDefault = array(
            'text' => '',
            'left' => 0,
            'top' => 0,
            'fontSize' => 32, //字号
            'fontColor' => '255,255,255', //字体颜色
            'angle' => 0,
        );
        $background = $config['background']; //海报最底层得背景
        //背景方法
        $backgroundInfo = getimagesize($background);
        $backgroundFun = 'imagecreatefrom' . image_type_to_extension($backgroundInfo[2], false);
        $background = $backgroundFun($background);
        $backgroundWidth = imagesx($background); //背景宽度
        $backgroundHeight = imagesy($background); //背景高度
        $imageRes = imageCreatetruecolor($backgroundWidth, $backgroundHeight);
        $color = imagecolorallocate($imageRes, 0, 0, 0);
        imagefill($imageRes, 0, 0, $color);
        imagecopyresampled($imageRes, $background, 0, 0, 0, 0, imagesx($background) , imagesy($background) , imagesx($background) , imagesy($background));
        //处理了图片
        if (!empty($config['image'])) {
            foreach ($config['image'] as $key => $val) {
                $val = array_merge($imageDefault, $val);
                $info = getimagesize($val['url']);
                $function = 'imagecreatefrom' . image_type_to_extension($info[2], false);
                if ($val['stream']) { //如果传的是字符串图像流
                    $info = getimagesizefromstring($val['url']);
                    $function = 'imagecreatefromstring';
                }
                $res = $function($val['url']);
                $resWidth = $info[0];
                $resHeight = $info[1];
                //建立画板 ,缩放图片至指定尺寸
                $canvas = imagecreatetruecolor($val['width'], $val['height']);
                imagefill($canvas, 0, 0, $color);
                //如果是透明的gif或png做透明处理
                $ext = pathinfo($val['url']);
                if (array_key_exists('extension',$ext)) {
                    if ($ext['extension'] == 'gif' || $ext['extension'] == 'png') {
                        // imageColorTransparent($canvas, $color); //颜色透明                     
                    }
                }
                //关键函数,参数(目标资源,源,目标资源的开始坐标x,y, 源资源的开始坐标x,y,目标资源的宽高w,h,源资源的宽高w,h)
                imagecopyresampled($canvas, $res, 0, 0, 0, 0, $val['width'], $val['height'], $resWidth, $resHeight);
                //$val['left'] = $val['left']<0?$backgroundWidth- abs($val['left']) - $val['width']:$val['left'];
                //如果left小于-1我这做成了计算让其水平居中
                if ($val['left'] < 0) {
                    $val['left'] = ceil($backgroundWidth - $val['width']) / 2;
                }
                $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) - $val['height'] : $val['top'];
                //放置图像
                imagecopymerge($imageRes, $canvas, $val['left'], $val['top'], $val['right'], $val['bottom'], $val['width'], $val['height'], $val['opacity']); //左,上,右,下,宽度,高度,透明度
                 
            }
        }
        //处理文字
        if (!empty($config['text'])) {
            foreach ($config['text'] as $key => $val) {
                $val = array_merge($textDefault, $val);
                list($R, $G, $B) = explode(',', $val['fontColor']);
                $fontColor = imagecolorallocate($imageRes, $R, $G, $B);
                //$val['left'] = $val['left']<0?$backgroundWidth- abs($val['left']):$val['left'];
                //如果left小于-1我这做成了计算让其水平居中
                if ($val['left'] < 0) {
                    $fontBox = imagettfbbox($val['fontSize'], 0, $val['fontPath'], $val['text']); //文字水平居中实质
                    $val['left'] = ceil(($backgroundWidth - $fontBox[2]) / 2); //计算文字的水平位置
                     
                }
                $val['top'] = $val['top'] < 0 ? $backgroundHeight - abs($val['top']) : $val['top'];
                imagettftext($imageRes, $val['fontSize'], $val['angle'], $val['left'], $val['top'], $fontColor, $val['fontPath'], $val['text']);
            }
        }
        //生成图片
        if (!empty($filename)) {
            $res = imagejpeg($imageRes, $filename, 90); //保存到本地
            imagedestroy($imageRes);
            if (!$res) return false;
            return $filename;
        } else {
            header("Content-type:image/png");
            imagejpeg($imageRes); //在浏览器上显示
            imagedestroy($imageRes);
        }
    }




}

3、批量发送邮件;

前端JS

javascript 复制代码
         // 批量发送邮件
            $(document).on("click", ".btn-sendemail", function () {
                let ids = Table.api.selectedids(table) //获取选中的条目ID集合
                ids.forEach(function(id,index) {
                    let row = Table.api.getrowbyid(table, id) //根据主键ID获取行数据                
                    if(row.send_email){
                        Toastr.error(row.name+'有发送记录');
                        return false;
                    }
                    if(!row.url_image){
                        Toastr.error(row.name+'无海报,请先生成');
                        return false;
                    }
                    $.ajax({
                        type: "GET",
                        url: 'miniform/guojihaibao/email_api?image='+row.url_image+'&email='+row.email+"&ids="+row.id,
                        cache: false,
                        success: function(data) {
                            Toastr.info(data.msg);
                        }
                      });
                });
                table.bootstrapTable('refresh',{});
            });

后端

javascript 复制代码
    /*
    *英文--提交email
    */
    public function email_api($ids=null,$email=null,$image=null){
        if (!preg_match('/^[^\s@]+@[^\s@]+\.[^\s@]+$/', $email)) $this->error('邮箱正则不通过');
        if(!$image) $this->error('无海报');
        $url = 'xxx';
        $title = 'VIP badge to participate the 53rd International Famous Furniture Fair (Dongguan)';
        $fsr='FURNITRUE FAIR (DONGGUAN)';
        // dump($image);
        $neirong = '<img src="'.cdnurl($image,true).'">';
        // $email = 'zhanpeng.wang@qq.com';
        $params = ['title'=>$title,'fsr'=>$fsr,'neirong'=>$neirong,'youxiang'=>$email];
        // dump($params);exit;
        $result = \fast\Http::post($url, $params);
        if($result){
            $result = json_decode($result,true);
            if($result['code']==200){
                $this->model->save(['send_email'=>time()],['id'=>$ids]);
                // $row = $this->model->get($ids);
                // dump();exit;
                // $row->send_email = time();
                // $row->save();
                $this->success($result['message']);
            }else{
                $this->error($result['message']);
            }
        }else{
            $this->error('API接口错误');
        }
    }

最终实现后台管理效果如下:

生成海报的效果

客户收到邮件的效果(每个邮件平台不一样,仅作参考)

相关推荐
java水泥工14 小时前
基于Echarts+HTML5可视化数据大屏展示-电信厅店营业效能分析
前端·echarts·html5·大屏展示
月光技术杂谈21 小时前
用Deepseek 实现一个基于web的扣图应用
前端·javascript·html5·ccs·tensorflow.js·canvas api
.生产的驴2 天前
React useEffect组件渲染执行操作 组件生命周期 监视器 副作用
前端·css·react.js·ajax·前端框架·jquery·html5
ZTLJQ3 天前
植物大战僵尸HTML5游戏完整实现教程
前端·游戏·html5
Hello123网站3 天前
300多个Html5小游戏列表和下载地址
前端·html·html5
rising start4 天前
前端基础一、HTML5
前端·html·html5
tryCbest4 天前
Html5实现弹出表单
html5
xhload3d5 天前
智慧钢厂高炉冶炼仿真分析 | 图扑数字孪生
3d·智慧城市·html5·webgl·数字孪生·可视化·热力图·智慧工厂·工业互联网·工业组态·高炉炼铁·数字工厂·高炉炉体·智慧高炉·高炉
繁花与尘埃6 天前
HTML5简介与基本骨架(本文为个人学习笔记,内容整理自哔哩哔哩UP主【非学者勿扰】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
笔记·学习·html5
无尽夏_7 天前
HTML5(前端基础)
前端·html·html5