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

news/2025/2/25 18:02:11/

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

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

实现步骤大概如下:

index页面增加三个按钮,三个按钮的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、批量获取登记数据;

后端

    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

 // 批量生成海报$(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',{});});

后端

    //生成海报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

<?phpnamespace 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

         // 批量发送邮件$(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',{});});

后端

    /**英文--提交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接口错误');}}

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

生成海报的效果

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


http://www.ppmy.cn/news/1574882.html

相关文章

基于大数据爬虫的旅游分析可视化平台设计和实现

# 当数据蜘蛛侠遇上旅游百事通&#xff1a;一场说走就走的技术狂欢 ## 引言&#xff1a;当旅游攻略遇上大数据&#xff0c;世界突然变得透明 去年国庆假期&#xff0c;小王在黄山之巅挤成"人肉三明治"时突然顿悟——如果能提前知道哪个景点即将爆满&#xff0c;哪个…

Linux----线程

一、基础概念对比 特性进程 (Process)线程 (Thread)资源分配资源分配的基本单位&#xff08;独立地址空间&#xff09;共享进程资源调度单位操作系统调度单位CPU调度的最小单位创建开销高&#xff08;需复制父进程资源&#xff09;低&#xff08;共享进程资源&#xff09;通信…

第五章:工程化实践 - 第一节 - Tailwind CSS 与前端框架的集成

Tailwind CSS 可以与各种现代前端框架完美配合。本节将详细介绍如何将 Tailwind CSS 集成到 React、Vue 和 Angular 等主流框架中&#xff0c;并介绍相关的最佳实践。 React 集成 基础配置 # 创建 React 项目 npx create-react-app my-app --template typescript# 安装 Tail…

DeepSeek+Kimi 一键生成100种PPT

一 简介 PPT在工作中经常用到&#xff0c;无论是给老板汇报&#xff0c;还是同事、朋友之间的分享&#xff0c;或是去见投资人:) &#xff0c;都离不开它&#xff0c;然而写PPT经常让人感觉不胜其烦&#xff0c;无论是逻辑的展开、还是页面的布局、字体、配图&#xff0c;都像个…

科技改变生活:未来趋势与应用解析

虚拟现实VR&#xff09;技术在教育领域的应用正日益受到关注。VR通过创造一个沉浸式环境&#xff0c;让学生参与到学习中&#xff0c;激发他们的兴趣。沉浸式学习是指学生在虚拟环境中体验和学习&#xff0c;通过这种方式&#xff0c;他们能够更好地理解知识。 首先&#xff0…

跳跃游戏(力扣55)

题目问是否可以跳到数组最后一个下标&#xff0c;有的同学可能会思考如何模拟跳跃这个操作&#xff0c;但这是比较困难的&#xff0c;很容易把自己绕进去。可以换一种思路&#xff0c;我们不需要知道具体是如何跳到最后一个下标的&#xff0c;而是找到最大的跳跃范围。如果该跳…

14.8 Auto-GPT 自主智能体设计解密:构建具备长期记忆的智能决策系统

Auto-GPT 自主智能体设计解密:构建具备长期记忆的智能决策系统 关键词:Auto-GPT 架构设计、自主智能体开发、LangChain Agents、长期记忆系统、工具链编排 1. 自主智能体的核心架构设计 Auto-GPT 系统架构图解: #mermaid-svg-NuDU1eo6sXqhA6Ve {font-family:"trebuch…

智能证件照处理器(深度学习)

功能说明:支持常见证件照尺寸(一寸、二寸、护照等) 智能背景去除(使用深度学习模型)自定义背景颜色选择自动调整尺寸并保持比例实时预览处理效果注意:整合rembg进行抠图,使用Pillow处理图像缩放和背景替换,定义常见证件照尺寸,并提供用户交互选项。首次运行时会自动下…