395 lines
13 KiB
PHP
395 lines
13 KiB
PHP
<?php
|
|
declare (strict_types=1);
|
|
|
|
namespace app\store\controller;
|
|
|
|
use app\store\model\Card as CardModel;
|
|
use app\store\model\card\CardPrint as CardPrintModel;
|
|
use think\facade\Filesystem;
|
|
use think\response\Json;
|
|
use Picqer\Barcode\BarcodeGeneratorPNG;
|
|
use setasign\Fpdi\Fpdi;
|
|
use setasign\Fpdi\PdfReader\PdfReader;
|
|
|
|
/**
|
|
* 充值卡控制器
|
|
* Class Card
|
|
* @package app\store\controller
|
|
*/
|
|
class Card extends Controller
|
|
{
|
|
/**
|
|
* 充值卡列表
|
|
* @return mixed
|
|
* @throws \think\exception\DbException
|
|
*/
|
|
public function index()
|
|
{
|
|
$model = new CardModel;
|
|
$getData = $this->request->param();
|
|
$data = [];
|
|
if (isset($getData['card_number']) && !empty($getData['card_number'])) {
|
|
$data[] = ['card_number', 'like', "%{$getData['card_number']}%"];
|
|
}
|
|
if (isset($getData['batch']) && !empty($getData['batch'])) {
|
|
$data[] = ['batch', 'like', "%{$getData['batch']}%"];
|
|
}
|
|
if (isset($getData['user_id']) && $getData['user_id']) {
|
|
$data[] = ['user_id', 'like', "%{$getData['user_id']}%"];
|
|
}
|
|
if (isset($getData['is_used']) && $getData['is_used'] > 0) {
|
|
$data[] = ['is_used', '=', "{$getData['is_used']}"];
|
|
}
|
|
if (isset($getData['is_print']) && $getData['is_print'] > -1) {
|
|
$data[] = ['is_print', '=', "{$getData['is_print']}"];
|
|
}
|
|
$data[] = ['is_delete', '=', 0];
|
|
$list = $model->getList($data);
|
|
return $this->renderSuccess(['list'=>$list]);
|
|
}
|
|
|
|
/**
|
|
* 获取所有充值卡
|
|
* @return mixed
|
|
* @throws \think\exception\DbException
|
|
*/
|
|
public function all(): Json
|
|
{
|
|
$user = $this->store['user'];
|
|
$list = CardModel::getAll($user);
|
|
return $this->renderSuccess(compact('list','user'));
|
|
}
|
|
|
|
/**
|
|
* 充值卡详情
|
|
* @param int $cardId
|
|
* @return Json
|
|
* @throws BaseException
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
* @throws \cores\exception\BaseException
|
|
*/
|
|
public function detail(int $cardId): Json
|
|
{
|
|
$cardInfo = CardModel::detail($cardId);
|
|
return $this->renderSuccess(compact('cardInfo'));
|
|
}
|
|
|
|
/**
|
|
* 删除充值卡
|
|
* @return Json
|
|
* @throws \think\exception\DbException
|
|
*/
|
|
public function delete(): Json
|
|
{
|
|
$arr = $this->postData();
|
|
foreach ((array)$arr as $val){
|
|
$model = CardModel::detail($val);
|
|
$model->setDelete();
|
|
}
|
|
return $this->renderSuccess('删除成功');
|
|
}
|
|
|
|
public function generateRandomString($length = 12, $big = false) {
|
|
$bytes = openssl_random_pseudo_bytes($length * 2); // 生成足够长的字节数
|
|
return $big ? strtoupper(substr(bin2hex($bytes), 0, $length)) : substr(bin2hex($bytes), 0, $length); // 转换并截取所需长度
|
|
}
|
|
|
|
/**
|
|
* 添加充值卡
|
|
* @return array|mixed
|
|
* @throws \think\Exception
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
* @throws \think\exception\DbException
|
|
*/
|
|
public function addCards()
|
|
{
|
|
$data = $this->postForm();
|
|
$pattern = '/^[1-9]\d*$/';
|
|
$amount = $data['amount'];
|
|
if(!preg_match($pattern,(string)$amount)){
|
|
return $this->renderError('充值卡金额必须是正整数');
|
|
}
|
|
if($amount <= 0){
|
|
return $this->renderError('充值卡金额不能小于等于0');
|
|
}
|
|
if($amount > 1000){
|
|
return $this->renderError('充值卡金额不能大于1000');
|
|
}
|
|
$cards = [];
|
|
$data = [];
|
|
$batch = $this->generateBatchNumber();
|
|
for ($i = 1;$i <= 18;$i++){
|
|
$cardNumber = $this->generateCardNumber(12,$cards); // 生成12位卡号
|
|
$plainSecretKey = $this->generateRandomString(16, true); // 生成16个字符长度的大写密钥
|
|
|
|
$data[] = [
|
|
'batch' => $batch,
|
|
'card_number' => $cardNumber,
|
|
'secret_key' => $plainSecretKey,
|
|
'amount' => $amount,
|
|
'file_path' => $this->generateBarcode($plainSecretKey),
|
|
];
|
|
$cards[] = $cardNumber;
|
|
}
|
|
$model = new CardModel;
|
|
// 新增记录
|
|
if (!$model->add($data,$this->store['user'])) {
|
|
return $this->renderError('添加充值卡失败');
|
|
}
|
|
$this->pdf($cards, $amount, $batch);
|
|
return $this->renderSuccess('成功添加18张充值卡');
|
|
}
|
|
|
|
/** 生成12位卡号
|
|
* @param int $length
|
|
* @param array $cards
|
|
* @return false|string
|
|
*/
|
|
public function generateCardNumber($length = 12, $cards = []) {
|
|
$timestamp = substr((string)(microtime(true) * 10000), -6); // 从时间戳中获取6位数
|
|
$randomNumber = str_pad((string)rand(0, 999999), 6, '0', STR_PAD_LEFT); // 随机生成6位数
|
|
|
|
// 合成卡号
|
|
$cardNumber = $timestamp . $randomNumber;
|
|
// 确保长度
|
|
$cardNumber = substr((string)$cardNumber, 0, $length);
|
|
// 校验数据库是否存在该卡号
|
|
if ($this->checkCardExists($cardNumber, $cards)) {
|
|
return $this->generateCardNumber($length, $cards); // 如果卡号已存在,重新生成
|
|
}
|
|
|
|
return $cardNumber;
|
|
}
|
|
/** 检查卡号是否存在
|
|
* @param string $cardNumber
|
|
* @param array $cards
|
|
* @return bool
|
|
*/
|
|
public function checkCardExists($cardNumber, $cards) {
|
|
return !(!in_array($cardNumber, $cards) && !CardModel::detail(['card_number'=>$cardNumber]));
|
|
}
|
|
|
|
/** 生成批次号
|
|
* @param string $prefix
|
|
* @return string
|
|
*/
|
|
function generateBatchNumber($prefix = 'CARD') {
|
|
$date = date('Ymd');
|
|
$randomNumber = str_pad((string)rand(0, 9999), 4, '0', STR_PAD_LEFT);
|
|
|
|
// 合成批次号,前缀 + 日期 + 随机数
|
|
return $prefix . $date . $randomNumber;
|
|
}
|
|
|
|
|
|
/**
|
|
* 修改充值卡使用状态
|
|
* @return String
|
|
*/
|
|
public function generateBarcode($key) {
|
|
// 确保密钥长度一致
|
|
$key = str_pad($key, 16, '0', STR_PAD_LEFT);
|
|
|
|
$generator = new BarcodeGeneratorPNG();
|
|
// 选择适当的条形码类型,例如 C128
|
|
$barcode = $generator->getBarcode($key, $generator::TYPE_CODE_128);
|
|
$name = $key.'.png';
|
|
$path = $this->getCardPath().$name;
|
|
|
|
|
|
|
|
// 在图像上绘制条形码
|
|
$barcodeImage = imagecreatefromstring($barcode);
|
|
|
|
// 创建一个空白图像,用于绘制条形码和编码文本
|
|
$barcodeWidth = imagesx($barcodeImage)+5;
|
|
$barcodeHeight = imagesy($barcodeImage);
|
|
$fontSize = 18; // 字体大小
|
|
$letterSpacing = 5; // 设置字符间距
|
|
$text = $key;
|
|
|
|
$image = imagecreate($barcodeWidth, $barcodeHeight + 20); // 额外留出20px高度用于编码文本
|
|
$backgroundColor = imagecolorallocate($image, 255, 255, 255); // 白色背景
|
|
$textColor = imagecolorallocate($image, 0, 0, 0); // 黑色文字
|
|
|
|
imagecopy($image, $barcodeImage, 0, 0, 0, 0, imagesx($barcodeImage), imagesy($barcodeImage));
|
|
|
|
// 在图像下方绘制编码文本
|
|
// 计算文本的总宽度(考虑字符间距)
|
|
$textWidth = (imagefontwidth($fontSize) + $letterSpacing) * strlen($text) - $letterSpacing;
|
|
|
|
// 计算文本的起始X坐标,使文本居中
|
|
$textX = ($barcodeWidth - $textWidth) / 2;
|
|
$textY = $barcodeHeight;
|
|
//imagestring($image, $fontSize, $textX, $textY, $text, $textColor);
|
|
|
|
// 绘制文本,逐个字符添加间距
|
|
for ($i = 0; $i < strlen($text); $i++) {
|
|
$xPos = intval($textX + ($i * (imagefontwidth($fontSize) + $letterSpacing)));
|
|
imagestring($image, $fontSize, $xPos, $textY, $text[$i], $textColor);
|
|
}
|
|
|
|
// 将图像保存为文件
|
|
imagepng($image, public_path().$path);
|
|
|
|
// 销毁图像资源
|
|
imagedestroy($image);
|
|
imagedestroy($barcodeImage);
|
|
|
|
|
|
// 将条形码保存为文件或输出
|
|
//file_put_contents(public_path().$path, $barcode);
|
|
return $path;
|
|
}
|
|
|
|
/**
|
|
* 获取兑换卡保存路径
|
|
* @return string
|
|
*/
|
|
private function getCardPath(): string
|
|
{
|
|
$filePath = 'uploads/card/' . date("Ymd") . '/';
|
|
!is_dir($filePath) && mkdir($filePath, 0755, true);
|
|
return $filePath;
|
|
}
|
|
|
|
/**
|
|
* 修改充值卡使用状态
|
|
* @return Json
|
|
*/
|
|
public function changeState(): Json
|
|
{
|
|
$post = $this->postData();
|
|
$is_used = $post['state']?20:10;
|
|
// 商品详情
|
|
foreach ((array)$post['cardIds'] as $card_id) {
|
|
$model = CardModel::detail($card_id);
|
|
if (!$model->changeStatus($is_used)) {
|
|
return $this->renderError('修改状态失败');
|
|
}
|
|
}
|
|
return $this->renderSuccess($post);
|
|
}
|
|
|
|
/** 填充pdf
|
|
* @param $cards
|
|
* @param $amount
|
|
* @param $batch
|
|
* @return string
|
|
*/
|
|
public function pdf($cards, $amount, $batch)
|
|
{
|
|
/*$sum = 0;
|
|
$money = 0;
|
|
// 商品详情
|
|
foreach ((array)$cards as $card_number) {
|
|
$model = CardModel::detail(['card_number'=>$card_number]);
|
|
if($money == 0){
|
|
$money = $model['amount'];
|
|
}
|
|
if($model['amount'] != $money){
|
|
return $this->renderError('请选择同一面额的兑换卡进行打印');
|
|
}
|
|
if ($model['is_used'] == 10 && $model['is_delete'] == 0 && $model['is_print'] == 0) {
|
|
$sum++;
|
|
}
|
|
}
|
|
if($sum != 18){
|
|
return $this->renderError('请选择18张兑换卡');
|
|
}*/
|
|
$result = [];
|
|
// 商品详情
|
|
foreach ((array)$cards as $card_number) {
|
|
$model = CardModel::detail(['card_number'=>$card_number]);
|
|
if ($model['is_used'] == 10 && $model['is_delete'] == 0 && $model['is_print'] == 0) {
|
|
$result[] = ['card_number'=>$model['card_number'],'file_path'=>$model['file_path'],'amount'=>(int)$model['amount']];
|
|
}
|
|
}
|
|
$url = $this->fillPdfTemplate($result, $amount);
|
|
CardPrintModel::add([
|
|
'file_path' => $url,
|
|
'amount' => $amount,
|
|
'batch' => $batch,
|
|
'num' => 18,
|
|
'store_user_id' => $this->store['user']['store_user_id'],
|
|
'store_id' => $this->storeId,
|
|
]);
|
|
return $url;
|
|
}
|
|
|
|
public function fillPdfTemplate($result, $amount)
|
|
{
|
|
// 创建 FPDI 对象
|
|
$pdf = new FPDI();
|
|
|
|
// 设置要导入的 PDF 模板文件路径
|
|
$templateFile = public_path().'uploads/template/template_'.$amount.'.pdf';
|
|
|
|
// 设置要导入的 PDF 模板文件
|
|
$pageCount = $pdf->setSourceFile($templateFile);
|
|
|
|
// import page 1
|
|
$tplIdx = $pdf->importPage(1);
|
|
// get the width and height of the template
|
|
$specs = $pdf->getTemplateSize($tplIdx);
|
|
// add a page
|
|
$pdf->AddPage($specs['orientation'], array($specs['width'], $specs['height']));
|
|
// use the imported page as the template
|
|
$pdf->useTemplate($tplIdx, 0, 0);
|
|
// now write some text above the imported page
|
|
|
|
$chunkedArray = array_chunk($result, 3);
|
|
|
|
// 初始坐标
|
|
$numberX = 24;
|
|
$numberY = 45;
|
|
|
|
$nxIncrement = 88.5;
|
|
$nyIncrement = 56.5;
|
|
|
|
$keyX = 46;
|
|
$keyY = 44;
|
|
// x坐标和y坐标的增量
|
|
$kxIncrement = 88.5;
|
|
$kyIncrement = 56.5;
|
|
|
|
|
|
|
|
// 循环每一排
|
|
for ($row = 0; $row < 6; $row++) {
|
|
|
|
// 计算当前行的y坐标
|
|
$ny = $numberY + $row * $nyIncrement;
|
|
$ky = $keyY + $row * $kyIncrement;
|
|
|
|
|
|
|
|
// 循环每一列
|
|
for ($col = 0; $col < 3; $col++) {
|
|
// 计算当前列的x坐标
|
|
$nx = $numberX + $col * $nxIncrement;
|
|
$kx = $keyX + $col * $kxIncrement;
|
|
|
|
// 输出结果
|
|
|
|
// 设置字体并填充文本
|
|
$pdf->SetFont('Arial', 'B', 7);
|
|
$pdf->SetXY($nx, $ny);
|
|
$pdf->Cell(0, 10, $chunkedArray[$row][$col]['card_number']);
|
|
|
|
// 填充图片
|
|
$imageFile = public_path().$chunkedArray[$row][$col]['file_path'];
|
|
|
|
$pdf->Image($imageFile, $kx, $ky, 55, 8);
|
|
}
|
|
}
|
|
$url = 'uploads/pdf/'.time().'.pdf';
|
|
// 输出填充后的 PDF
|
|
$pdf->Output('F', public_path().$url);
|
|
return $url;
|
|
}
|
|
}
|