记录一个海报批量生成、邮件批量发送功能开发,业务场景如下:
国外客户做观展预登记,工作人员通过后台,批量给这些观众生成入场证件并发送到观众登记的邮箱,以方便观众入场时快速进场。证件信息包含入场二维码、姓名;需要批量生成证件和批量发送邮件功能。
实现步骤大概如下:
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
<?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
// 批量发送邮件
$(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接口错误');
}
}
最终实现后台管理效果如下:
生成海报的效果
客户收到邮件的效果(每个邮件平台不一样,仅作参考)